├── .github └── workflows │ └── kotlin.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src ├── commonMain └── kotlin │ └── com │ └── quickbirdstudios │ └── nonEmptyCollection │ ├── NonEmptyCollection.kt │ ├── NonEmptyCollectionOperators.kt │ ├── list │ ├── NonEmptyList+plus.kt │ ├── NonEmptyList.kt │ ├── NonEmptyListOperators.kt │ └── nonEmptyListOf.kt │ ├── map │ ├── NonEmptyMap+plus.kt │ ├── NonEmptyMap.kt │ ├── NonEmptyMapOperators.kt │ └── nonEmptyMapOf.kt │ ├── set │ ├── NonEmptySet+plus.kt │ ├── NonEmptySet.kt │ ├── NonEmptySetOperators.kt │ └── nonEmptySetOf.kt │ ├── toNonEmptyOr.kt │ ├── toNonEmptyOrNull.kt │ └── unsafe │ ├── Function+addUnitParameter.kt │ ├── UnsafeNonEmptyCollectionApi.kt │ ├── toNonEmptyCollection.kt │ ├── wrapListOperator.kt │ ├── wrapMapOperator.kt │ └── wrapSetOperator.kt ├── jvmMain └── kotlin │ └── com │ └── quickbirdstudios │ └── nonEmptyCollection │ └── NonEmptyCollection+shuffled.kt └── jvmTest └── kotlin └── com └── quickbirdstudios └── nonEmptyCollection ├── NonEmptyCollectionsOperatorTest.kt ├── ToNonEmptyOrNullTest.kt ├── ToNonEmptyOrTest.kt ├── assertOperationEquals.kt ├── assertThrows.kt ├── list ├── NonEmptyListOfTest.kt ├── NonEmptyListOperatorsTest.kt ├── NonEmptyListPlusTest.kt ├── NonEmptyListTest.kt └── assertListOperationEquals.kt ├── map ├── NonEmptyMapOfTest.kt ├── NonEmptyMapOperatorsTest.kt ├── NonEmptyMapPlusTest.kt ├── NonEmptyMapTest.kt └── assertMapOperationEquals.kt ├── set ├── NonEmptySetOfTest.kt ├── NonEmptySetOperatorsTest.kt ├── NonEmptySetPlusTest.kt ├── NonEmptySetTest.kt └── assertSetOperationEquals.kt └── unsafe ├── AddUnitParameterTest.kt └── ToNonEmptyCollectionTest.kt /.github/workflows/kotlin.yml: -------------------------------------------------------------------------------- 1 | name: Run jvm tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: set up JDK 1.8 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 1.8 20 | - name: Grant execute permission for gradlew 21 | run: chmod +x gradlew 22 | - name: Build with Gradle 23 | run: ./gradlew build 24 | - name: Run jvm test 25 | run: ./gradlew :cleanJvmTest :jvmTest 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | 3 | *.iml 4 | /local.properties 5 | .DS_Store 6 | 7 | .idea/* 8 | !.idea/codeStyles/ 9 | !.idea/dictionaries/ 10 | .idea/codeStyles/codeStyleConfig.xml 11 | !.idea/icon.png 12 | 13 | ### Gradle template 14 | /build/ 15 | 16 | # Ignore Gradle GUI config 17 | gradle-app.setting 18 | 19 | # Cache of project 20 | .gradletasknamecache 21 | 22 | # File-based project format 23 | *.iws 24 | 25 | # IntelliJ 26 | out/ 27 | 28 | # mpeltonen/sbt-idea plugin 29 | .idea_modules/ 30 | 31 | ### Android template 32 | # Built application files 33 | *.apk 34 | *.ap_ 35 | 36 | # Files for the ART/Dalvik VM 37 | *.dex 38 | 39 | # Java class files 40 | *.class 41 | 42 | # Generated files 43 | bin/ 44 | gen/ 45 | 46 | # Gradle files 47 | .gradle/ 48 | build/ 49 | 50 | # Local configuration file (sdk path, etc) 51 | local.properties 52 | 53 | # Proguard folder generated by Eclipse 54 | proguard/ 55 | 56 | # Log Files 57 | *.log 58 | 59 | # Android Studio Navigation editor temp files 60 | .navigation/ 61 | 62 | # Android Studio captures folder 63 | captures/ 64 | 65 | # Keystore files 66 | # Uncomment the following line if you do not want to check your keystore files in. 67 | #*.jks 68 | 69 | # External native build folder generated in Android Studio 2.2 and later 70 | 71 | # Google Services (e.g. APIs or Firebase) 72 | google-services.json 73 | 74 | 75 | # Mobile Tools for Java (J2ME) 76 | .mtj.tmp/ 77 | 78 | # Package Files # 79 | *.jar 80 | *.war 81 | *.nar 82 | *.ear 83 | *.zip 84 | *.tar.gz 85 | *.rar 86 | 87 | !gradle-wrapper.jar 88 | /projectFilesBackup/ 89 | !libs/*.jar 90 | 91 | !.idea/runConfigurations 92 | 93 | classes 94 | *.asv 95 | 96 | desktop.ini 97 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 QuickBird Studios 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NonEmptyCollections 2 | ## Making the world a little more type-safe 🌍🏆 3 | 4 | ![Cover Image](https://user-images.githubusercontent.com/74978506/112829487-7d31b780-9091-11eb-8182-c5a12ff46a8e.png) 5 | 6 | Reduce the need for emptiness checks and reduce unsafe APIs with **NonEmptyCollections**. 7 | 8 | You can use `NonEmptyList`, `NonEmptySet` and `NonEmptyMap` to restrict the input of functions to make your code safer and avoid unnecessary runtime exceptions. 9 | 10 | For a detailed explanation see our related article [Non-Empty Lists in Kotlin](https://quickbirdstudios.com/blog/non-empty-lists-kotlin). 11 | 12 | This is an early version and work in progress. Do not hesitate to give feedback, ideas or improvements via an issue. 13 | 14 | # Examples 15 | 16 | ## Average without exceptions 17 | 18 | With the `NonEmptyList` type, we can make sure that at least one element is always a list. If we want to calculate the average of that list, it is impossible to compile a program where an invalid input is passed to our function. 19 | 20 | ```kotlin 21 | fun NonEmptyList.average() = sum() / size 22 | ``` 23 | 24 | ```kotlin 25 | nonEmptyListOf().average() // This does not compile! ❌ 26 | 27 | nonEmptyListOf(1, 2, 3).average() // This does! ✅ 28 | ``` 29 | 30 | ## Non-empty Shopping-Cart 31 | 32 | Let's imagine an online shop, where you can put articles into a shopping cart. If you have some articles in the shopping cart, you should be able to share the articles with your friends, save them for later on a wish list or directly buy them. But these three features just make sense if the shopping cart is not empty. Wouldn't it be cool to already prevent at compile-time that somebody tries these features with an empty set of articles? 33 | 34 | ```kotlin 35 | sealed class ShoppingCart { 36 | object Empty : ShoppingCart() 37 | 38 | data class Filled( 39 | val articles: NonEmptySet
40 | ) : ShoppingCart() { 41 | 42 | fun buy(paymentType: PaymentType) = articles.buy(paymentType) 43 | fun share() = articles.share() 44 | fun saveTo(wishList: WishList) = articles.saveTo(wishList) 45 | } 46 | } 47 | 48 | fun NonEmptyCollection
.buy(paymentType: PaymentType) { 💸 } 49 | 50 | fun NonEmptyCollection
.share() { 💬 } 51 | 52 | fun NonEmptyCollection
.saveTo(wishList: WishList) { 💾 } 53 | ``` 54 | 55 | The devs, who implement `buy`, `share` and `saveTo` don't have to handle the empty case. The consumers of these APIs don't have to think of exception handling, because they are forced by the compiler to provide a valid input. We would say, that's a win-win situation 🏆. 56 | 57 | # 🏃 Library Setup 58 | ## 1. Add the repository 59 | `build.gradle.kts` 60 | 61 | ```kotlin 62 | allprojects { 63 | repositories { 64 | ... 65 | maven { url = uri("https://jitpack.io") } 66 | } 67 | } 68 | ``` 69 | 70 | ## 2. Add the dependency 71 | `build.gradle.kts` 72 | 73 | ```kotlin 74 | dependencies { 75 | ... 76 | implementation("com.github.quickbirdstudios.NonEmptyCollections:NonEmptyCollections:1.1.0") 77 | } 78 | ``` 79 | 80 | # 👤 Author 81 | This Kotlin library is created with ❤️ by [QuickBird Studios](https://quickbirdstudios.com/). 82 | 83 | # ❤️ Contributing 84 | Open an issue if you need help, if you found a bug, or if you want to discuss a feature request. 85 | 86 | Open a PR if you want to make changes to NonEmptyCollections. 87 | 88 | # 📃 License 89 | NonEmptyCollections is released under an MIT license. See [License](LICENSE) for more information. 90 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon 2 | 3 | plugins { 4 | kotlin("multiplatform") version "1.4.30" 5 | `maven-publish` 6 | } 7 | 8 | group = "com.quickbirdstudios" 9 | version = "1.0" 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | kotlin { 16 | jvm { 17 | compilations.all { 18 | kotlinOptions.jvmTarget = "1.8" 19 | } 20 | testRuns["test"].executionTask.configure { 21 | useJUnit() 22 | } 23 | } 24 | js(LEGACY) { 25 | browser { 26 | commonWebpackConfig { 27 | cssSupport.enabled = true 28 | } 29 | } 30 | } 31 | val hostOs = System.getProperty("os.name") 32 | val isMingwX64 = hostOs.startsWith("Windows") 33 | val nativeTarget = when { 34 | hostOs == "Mac OS X" -> macosX64("native") 35 | hostOs == "Linux" -> linuxX64("native") 36 | isMingwX64 -> mingwX64("native") 37 | else -> throw GradleException("Host OS is not supported in Kotlin/Native.") 38 | } 39 | 40 | sourceSets { 41 | val commonMain by getting 42 | val commonTest by getting { 43 | dependencies { 44 | implementation(kotlin("test-common")) 45 | implementation(kotlin("test-annotations-common")) 46 | } 47 | } 48 | val jvmMain by getting 49 | val jvmTest by getting { 50 | dependencies { 51 | implementation(kotlin("test-junit")) 52 | } 53 | } 54 | val jsMain by getting 55 | val jsTest by getting { 56 | dependencies { 57 | implementation(kotlin("test-js")) 58 | } 59 | } 60 | val nativeMain by getting 61 | val nativeTest by getting 62 | } 63 | 64 | tasks.withType().configureEach { 65 | kotlinOptions { 66 | freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn" 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | kotlin.mpp.enableGranularSourceSetsMetadata=true 3 | kotlin.native.enableDependencyPropagation=false 4 | kotlin.js.generate.executable.default=false 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuickBirdEng/NonEmptyCollections/d8ea1d6dff7914a374927ecd92df0efb348abca7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "NonEmptyCollections" 3 | 4 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/NonEmptyCollection.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection 2 | 3 | interface NonEmptyCollection : Collection { 4 | 5 | @Deprecated( 6 | level = DeprecationLevel.ERROR, 7 | message = "Is never null!", 8 | replaceWith = ReplaceWith("first()") 9 | ) 10 | fun firstOrNull(): T = first() 11 | } 12 | 13 | @Deprecated( 14 | level = DeprecationLevel.ERROR, 15 | message = "Alternative is never used!", 16 | replaceWith = ReplaceWith("first()") 17 | ) 18 | 19 | fun NonEmptyCollection.firstOr(alternative: () -> T): T = first() 20 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/NonEmptyCollectionOperators.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package com.quickbirdstudios.nonEmptyCollection 4 | 5 | fun > NonEmptyCollection.max() = maxOrNull()!! 6 | 7 | fun NonEmptyCollection.max() = maxOrNull()!! 8 | 9 | fun NonEmptyCollection.max() = maxOrNull()!! 10 | 11 | fun > NonEmptyCollection.maxBy(selector: (T) -> R) = maxByOrNull(selector)!! 12 | 13 | fun > NonEmptyCollection.min() = minOrNull()!! 14 | 15 | fun NonEmptyCollection.min() = minOrNull()!! 16 | 17 | fun NonEmptyCollection.min() = minOrNull()!! 18 | 19 | fun > NonEmptyCollection.minBy(selector: (T) -> R) = minByOrNull(selector)!! 20 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/list/NonEmptyList+plus.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.list 2 | 3 | import kotlin.collections.plus as stdPlus 4 | 5 | operator fun NonEmptyList.plus(value: T): NonEmptyList = full + value 6 | 7 | operator fun List.plus(value: T): NonEmptyList = NonEmptyList(this.stdPlus(value)) 8 | 9 | operator fun NonEmptyList.plus( 10 | other: Iterable 11 | ): NonEmptyList = NonEmptyList(full.stdPlus(other)) 12 | 13 | operator fun List.plus( 14 | other: NonEmptyList 15 | ): NonEmptyList = NonEmptyList(this.stdPlus(other.full)) 16 | 17 | operator fun NonEmptyList.plus( 18 | other: NonEmptyList 19 | ): NonEmptyList = full + other 20 | 21 | operator fun NonEmptyList.plus( 22 | other: Sequence 23 | ): NonEmptyList = NonEmptyList( 24 | ArrayList(full.size).apply { 25 | addAll(full) 26 | addAll(other) 27 | } 28 | ) 29 | 30 | operator fun NonEmptyList.plus( 31 | other: Array 32 | ): NonEmptyList = NonEmptyList( 33 | ArrayList(full.size + other.size).apply { 34 | addAll(full) 35 | addAll(other) 36 | } 37 | ) 38 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/list/NonEmptyList.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.list 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 4 | 5 | class NonEmptyList internal constructor( 6 | internal val full: List 7 | ) : List by full, NonEmptyCollection { 8 | 9 | internal constructor( 10 | head: T, 11 | tail: List 12 | ) : this( 13 | full = ArrayList(tail.size + 1).apply { 14 | add(head) 15 | addAll(tail) 16 | } 17 | ) 18 | 19 | init { 20 | require(full.isNotEmpty()) { 21 | "Fatal Error! This is a bug. Please contact the library author." 22 | } 23 | } 24 | 25 | override fun toString(): String = full.toString() 26 | 27 | override fun equals(other: Any?): Boolean = full == other 28 | 29 | override fun hashCode(): Int = full.hashCode() 30 | } 31 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/list/NonEmptyListOperators.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(UnsafeNonEmptyCollectionApi::class) 2 | @file:Suppress("unused") 3 | 4 | package com.quickbirdstudios.nonEmptyCollection.list 5 | 6 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 7 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 8 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyList 9 | import com.quickbirdstudios.nonEmptyCollection.unsafe.wrapOperator 10 | 11 | fun NonEmptyCollection.toNonEmptyList(): NonEmptyList = toNonEmptyList() 12 | 13 | fun NonEmptyCollection.asReversed(): NonEmptyList = wrapOperator(List::asReversed) 14 | 15 | fun > NonEmptyCollection.sorted() = wrapOperator(Iterable::sorted) 16 | 17 | fun > NonEmptyCollection.sortedBy( 18 | selector: (T) -> R? 19 | ) = wrapOperator(selector, Iterable::sortedBy) 20 | 21 | fun NonEmptyCollection.sortedWith( 22 | comparator: Comparator 23 | ) = wrapOperator(comparator, Iterable::sortedWith) 24 | 25 | fun > NonEmptyCollection.sortedDescending() = 26 | wrapOperator(Iterable::sortedDescending) 27 | 28 | fun > NonEmptyCollection.sortedByDescending( 29 | selector: (T) -> R? 30 | ) = wrapOperator(selector, Iterable::sortedByDescending) 31 | 32 | fun NonEmptyList.onEach( 33 | action: (T) -> Unit 34 | ) = wrapOperator(action, List::onEach) 35 | 36 | fun NonEmptyList.onEachIndexed( 37 | action: (index: Int, T) -> Unit 38 | ) = wrapOperator(action, List::onEachIndexed) 39 | 40 | fun NonEmptyCollection.map( 41 | transform: (T) -> R 42 | ) = wrapOperator(transform, Iterable::map) 43 | 44 | fun NonEmptyCollection.mapIndexed( 45 | transform: (index: Int, T) -> R 46 | ) = wrapOperator(transform, Iterable::mapIndexed) 47 | 48 | fun NonEmptyCollection.flatMap( 49 | transform: (T) -> NonEmptyList 50 | ): NonEmptyList = wrapOperator(transform, Iterable::flatMap) 51 | 52 | fun NonEmptyCollection.flatMapIndexed( 53 | transform: (index: Int, T) -> NonEmptyList 54 | ) = wrapOperator(transform, Iterable::flatMapIndexed) 55 | 56 | fun NonEmptyCollection.scan( 57 | initial: R, 58 | operation: (acc: R, T) -> R 59 | ) = wrapOperator(initial, operation, Iterable::scan) 60 | 61 | fun NonEmptyCollection.scanIndexed( 62 | initial: R, 63 | operation: (index: Int, acc: R, T) -> R 64 | ) = wrapOperator(initial, operation, Iterable::scanIndexed) 65 | 66 | fun NonEmptyCollection.runningReduce( 67 | operation: (acc: S, T) -> S 68 | ) = wrapOperator(operation, Iterable::runningReduce) 69 | 70 | fun NonEmptyCollection.runningReduceIndexed( 71 | operation: (index: Int, acc: S, T) -> S 72 | ) = wrapOperator(operation, Iterable::runningReduceIndexed) 73 | 74 | fun NonEmptyCollection.runningFold( 75 | initial: R, 76 | operation: (acc: R, T) -> R 77 | ) = wrapOperator(initial, operation, Iterable::runningFold) 78 | 79 | fun NonEmptyCollection.runningFoldIndexed( 80 | initial: R, 81 | operation: (index: Int, acc: R, T) -> R 82 | ) = wrapOperator(initial, operation, Iterable::runningFoldIndexed) 83 | 84 | fun NonEmptyCollection>.flatten() = 85 | wrapOperator(Iterable>::flatten) 86 | 87 | fun NonEmptyCollection.reversed() = wrapOperator(Iterable::reversed) 88 | 89 | fun NonEmptyCollection.zip(other: NonEmptyCollection) = 90 | wrapOperator(other, Iterable::zip) 91 | 92 | fun NonEmptyCollection.chunked( 93 | size: Int 94 | ): NonEmptyList> = wrapOperator(size, Iterable::chunked) 95 | .map { chunk -> chunk.toNonEmptyList() } 96 | 97 | fun NonEmptyCollection.chunked( 98 | size: Int, 99 | transform: (List) -> R 100 | ) = wrapOperator(size, transform, Iterable::chunked) 101 | 102 | fun NonEmptyList.withIndex(): NonEmptyList> { 103 | val operation = { iterable: Iterable -> iterable.withIndex().toList() } 104 | return wrapOperator(operation) 105 | } 106 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/list/nonEmptyListOf.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package com.quickbirdstudios.nonEmptyCollection.list 4 | 5 | fun nonEmptyListOf(value: T, vararg values: T) = nonEmptyListOf(value, values.asList()) 6 | 7 | fun nonEmptyListOf(value: T, values: List) = NonEmptyList(value, values) 8 | 9 | fun nonEmptyListOfNotNull( 10 | value: T, 11 | vararg values: T? 12 | ) = nonEmptyListOfNotNull(value, values.asList()) 13 | 14 | fun nonEmptyListOfNotNull( 15 | value: T, 16 | values: List 17 | ) = NonEmptyList(value, values.filterNotNull()) 18 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/map/NonEmptyMap+plus.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.map 2 | 3 | import kotlin.collections.plus as stdPlus 4 | 5 | operator fun NonEmptyMap.plus(entry: Pair): NonEmptyMap = full + entry 6 | 7 | operator fun Map.plus( 8 | entry: Pair 9 | ): NonEmptyMap = NonEmptyMap(this.stdPlus(entry)) 10 | 11 | operator fun NonEmptyMap.plus( 12 | other: Map 13 | ): NonEmptyMap = NonEmptyMap(full.stdPlus(other)) 14 | 15 | operator fun Map.plus( 16 | other: NonEmptyMap 17 | ): NonEmptyMap = NonEmptyMap(this.stdPlus(other.full)) 18 | 19 | operator fun NonEmptyMap.plus( 20 | other: NonEmptyMap 21 | ): NonEmptyMap = full + other 22 | 23 | operator fun NonEmptyMap.plus( 24 | other: Iterable> 25 | ): NonEmptyMap = NonEmptyMap(full.stdPlus(other)) 26 | 27 | operator fun NonEmptyMap.plus( 28 | other: Sequence> 29 | ): NonEmptyMap = NonEmptyMap(full.stdPlus(other)) 30 | 31 | operator fun NonEmptyMap.plus( 32 | other: Array> 33 | ): NonEmptyMap = NonEmptyMap(full.stdPlus(other)) 34 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/map/NonEmptyMap.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.map 2 | 3 | class NonEmptyMap internal constructor( 4 | internal val full: Map 5 | ) : Map by full { 6 | 7 | internal constructor( 8 | first: Pair, 9 | rest: Map 10 | ) : this( 11 | full = LinkedHashMap(rest.size + 1).apply { 12 | put(first.first, first.second) 13 | putAll(rest) 14 | } 15 | ) 16 | 17 | init { 18 | require(full.isNotEmpty()) { 19 | "Fatal Error! This is a bug. Please contact the library author." 20 | } 21 | } 22 | 23 | override fun toString(): String = full.toString() 24 | 25 | override fun equals(other: Any?): Boolean = full == other 26 | 27 | override fun hashCode(): Int = full.hashCode() 28 | } 29 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/map/NonEmptyMapOperators.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(UnsafeNonEmptyCollectionApi::class) 2 | @file:Suppress("unused") 3 | 4 | package com.quickbirdstudios.nonEmptyCollection.map 5 | 6 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 7 | import com.quickbirdstudios.nonEmptyCollection.list.NonEmptyList 8 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 9 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyMap 10 | import com.quickbirdstudios.nonEmptyCollection.unsafe.wrapOperator 11 | 12 | fun NonEmptyCollection>.toNonEmptyMap(): NonEmptyMap = toNonEmptyMap() 13 | 14 | fun NonEmptyMap.onEach( 15 | action: (Map.Entry) -> Unit 16 | ): NonEmptyMap = wrapOperator(action, Map::onEach) 17 | 18 | fun NonEmptyMap.onEachIndexed( 19 | action: (index: Int, Map.Entry) -> Unit 20 | ): NonEmptyMap = wrapOperator(action, Map::onEachIndexed) 21 | 22 | fun NonEmptyCollection.associate( 23 | transform: (T) -> Pair 24 | ): NonEmptyMap = wrapOperator(transform, Iterable::associate) 25 | 26 | fun NonEmptyCollection.associateWith( 27 | valueSelector: (K) -> V 28 | ): NonEmptyMap = wrapOperator(valueSelector, Iterable::associateWith) 29 | 30 | fun NonEmptyCollection.associateBy( 31 | keySelector: (V) -> K 32 | ): NonEmptyMap = wrapOperator(keySelector, Iterable::associateBy) 33 | 34 | fun NonEmptyMap.mapValues( 35 | transform: (Map.Entry) -> R 36 | ): NonEmptyMap = wrapOperator(transform, Map::mapValues) 37 | 38 | fun NonEmptyMap.mapKeys( 39 | transform: (Map.Entry) -> R 40 | ): NonEmptyMap = wrapOperator(transform, Map::mapKeys) 41 | 42 | fun NonEmptyMap.map( 43 | transform: (Map.Entry) -> R 44 | ): NonEmptyList = wrapOperator(transform, Map::map) 45 | 46 | fun > NonEmptyMap.maxBy( 47 | selector: (Map.Entry) -> R 48 | ): Map.Entry = maxByOrNull(selector)!! 49 | 50 | fun > NonEmptyMap.minBy( 51 | selector: (Map.Entry) -> R 52 | ): Map.Entry = minByOrNull(selector)!! 53 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/map/nonEmptyMapOf.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package com.quickbirdstudios.nonEmptyCollection.map 4 | 5 | fun nonEmptyMapOf( 6 | entry: Pair, 7 | vararg entries: Pair 8 | ) = NonEmptyMap( 9 | first = entry, 10 | rest = mapOf(*entries) 11 | ) 12 | 13 | fun nonEmptyMapOf( 14 | entry: Pair, 15 | entries: Map 16 | ) = NonEmptyMap( 17 | first = entry, 18 | rest = entries 19 | ) 20 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/set/NonEmptySet+plus.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.set 2 | 3 | import kotlin.collections.plus as stdPlus 4 | 5 | operator fun NonEmptySet.plus(value: T): NonEmptySet = full + value 6 | 7 | operator fun Set.plus(value: T): NonEmptySet = NonEmptySet(this.stdPlus(value)) 8 | 9 | operator fun NonEmptySet.plus(other: Set) = NonEmptySet(full.stdPlus(other)) 10 | 11 | operator fun Set.plus( 12 | other: NonEmptySet 13 | ): NonEmptySet = NonEmptySet(this.stdPlus(other.full)) 14 | 15 | operator fun NonEmptySet.plus( 16 | other: NonEmptySet 17 | ): NonEmptySet = this + other.full 18 | 19 | operator fun NonEmptySet.plus( 20 | other: Iterable 21 | ): NonEmptySet = NonEmptySet(full.stdPlus(other)) 22 | 23 | operator fun NonEmptySet.plus( 24 | other: Sequence 25 | ): NonEmptySet = NonEmptySet(full.stdPlus(other)) 26 | 27 | operator fun NonEmptySet.plus( 28 | other: Array 29 | ): NonEmptySet = NonEmptySet(full.stdPlus(other)) 30 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/set/NonEmptySet.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.set 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 4 | 5 | class NonEmptySet internal constructor( 6 | internal val full: Set 7 | ) : Set by full, NonEmptyCollection { 8 | 9 | internal constructor( 10 | first: T, 11 | rest: Set 12 | ) : this( 13 | full = HashSet(rest.size + 1).apply { 14 | add(first) 15 | addAll(rest) 16 | } 17 | ) 18 | 19 | override fun toString(): String = full.toString() 20 | 21 | override fun equals(other: Any?): Boolean = full == other 22 | 23 | override fun hashCode(): Int = full.hashCode() 24 | 25 | init { 26 | require(full.isNotEmpty()) { 27 | "Fatal Error! This is a bug. Please contact the library author." 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/set/NonEmptySetOperators.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(UnsafeNonEmptyCollectionApi::class) 2 | @file:Suppress("unused") 3 | 4 | package com.quickbirdstudios.nonEmptyCollection.set 5 | 6 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 7 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 8 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptySet 9 | import com.quickbirdstudios.nonEmptyCollection.unsafe.wrapOperator 10 | 11 | fun NonEmptyCollection.toNonEmptySet(): NonEmptySet = toNonEmptySet() 12 | 13 | fun NonEmptySet.onEach( 14 | action: (T) -> Unit 15 | ): NonEmptySet = wrapOperator(action, Set::onEach) 16 | 17 | fun NonEmptySet.onEachIndexed( 18 | action: (index: Int, T) -> Unit 19 | ): NonEmptySet = wrapOperator(action, Set::onEachIndexed) 20 | 21 | fun NonEmptyCollection.union(other: Iterable): NonEmptySet = 22 | wrapOperator(other, Iterable::union) 23 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/set/nonEmptySetOf.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package com.quickbirdstudios.nonEmptyCollection.set 4 | 5 | fun nonEmptySetOf(value: T, vararg values: T) = nonEmptySetOf(value, values.toSet()) 6 | 7 | fun nonEmptySetOf(value: T, values: Set): NonEmptySet = NonEmptySet(value, values) 8 | 9 | fun nonEmptySetOfNotNull( 10 | value: T, 11 | vararg values: T? 12 | ) = nonEmptySetOfNotNull(value, setOf(*values)) 13 | 14 | fun nonEmptySetOfNotNull( 15 | value: T, 16 | values: Set 17 | ) = NonEmptySet(value, values.filterNotNull().toSet()) 18 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/toNonEmptyOr.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(UnsafeNonEmptyCollectionApi::class) 2 | @file:Suppress("unused") 3 | 4 | package com.quickbirdstudios.nonEmptyCollection 5 | 6 | import com.quickbirdstudios.nonEmptyCollection.list.NonEmptyList 7 | import com.quickbirdstudios.nonEmptyCollection.map.NonEmptyMap 8 | import com.quickbirdstudios.nonEmptyCollection.set.NonEmptySet 9 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 10 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyList 11 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyMap 12 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptySet 13 | 14 | fun List.toNonEmptyListOr( 15 | alternative: List.() -> NonEmptyList 16 | ) = if (isEmpty()) alternative() else toNonEmptyList() 17 | 18 | fun Set.toNonEmptySetOr( 19 | alternative: Set.() -> NonEmptySet 20 | ) = if (isEmpty()) alternative() else toNonEmptySet() 21 | 22 | fun Map.toNonEmptyMapOr( 23 | alternative: Map.() -> NonEmptyMap 24 | ) = if (isEmpty()) alternative() else toNonEmptyMap() 25 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/toNonEmptyOrNull.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | @file:OptIn(UnsafeNonEmptyCollectionApi::class) 3 | 4 | package com.quickbirdstudios.nonEmptyCollection 5 | 6 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 7 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyList 8 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyMap 9 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptySet 10 | 11 | fun List.toNonEmptyListOrNull() = if (isEmpty()) null else toNonEmptyList() 12 | 13 | fun Set.toNonEmptyMapOrNull() = if (isEmpty()) null else toNonEmptySet() 14 | 15 | fun Map.toNonEmptyMapOrNull() = if (isEmpty()) null else toNonEmptyMap() 16 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/unsafe/Function+addUnitParameter.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("NOTHING_TO_INLINE") 2 | 3 | package com.quickbirdstudios.nonEmptyCollection.unsafe 4 | 5 | inline fun (() -> O).addUnitParameter() = { _: Unit -> this() } 6 | 7 | inline fun ((I) -> O).addUnitParameter() = { input: I, _: Unit -> this(input) } 8 | 9 | inline fun ((I1, I2) -> O).addUnitParameter() = { input1: I1, input2: I2, _: Unit -> 10 | this(input1, input2) 11 | } 12 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/unsafe/UnsafeNonEmptyCollectionApi.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.unsafe 2 | 3 | @RequiresOptIn 4 | annotation class UnsafeNonEmptyCollectionApi 5 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/unsafe/toNonEmptyCollection.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.unsafe 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.list.NonEmptyList 4 | import com.quickbirdstudios.nonEmptyCollection.list.nonEmptyListOf 5 | import com.quickbirdstudios.nonEmptyCollection.map.NonEmptyMap 6 | import com.quickbirdstudios.nonEmptyCollection.map.nonEmptyMapOf 7 | import com.quickbirdstudios.nonEmptyCollection.set.NonEmptySet 8 | import com.quickbirdstudios.nonEmptyCollection.set.nonEmptySetOf 9 | 10 | @UnsafeNonEmptyCollectionApi 11 | fun Iterable.toNonEmptyList(): NonEmptyList = isAlreadyNonEmptyOr { 12 | NonEmptyList(toList()) 13 | } 14 | 15 | @UnsafeNonEmptyCollectionApi 16 | fun Iterable.toNonEmptySet(): NonEmptySet = isAlreadyNonEmptyOr { 17 | toSet().toNonEmptySet() 18 | } 19 | 20 | @UnsafeNonEmptyCollectionApi 21 | fun Set.toNonEmptySet(): NonEmptySet = isAlreadyNonEmptyOr { 22 | NonEmptySet(this) 23 | } 24 | 25 | @UnsafeNonEmptyCollectionApi 26 | fun Iterable>.toNonEmptyMap(): NonEmptyMap = isAlreadyNonEmptyOr { 27 | toMap().toNonEmptyMap() 28 | } 29 | 30 | @UnsafeNonEmptyCollectionApi 31 | fun Map.toNonEmptyMap(): NonEmptyMap = isAlreadyNonEmptyOr { 32 | NonEmptyMap(this) 33 | } 34 | 35 | private inline fun Empty.isAlreadyNonEmptyOr( 36 | transform: Empty.() -> NonEmpty 37 | ) = if (this is NonEmpty) this else transform(this) 38 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/unsafe/wrapListOperator.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(ExperimentalTypeInference::class) 2 | 3 | package com.quickbirdstudios.nonEmptyCollection.unsafe 4 | 5 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 6 | import com.quickbirdstudios.nonEmptyCollection.list.NonEmptyList 7 | import kotlin.experimental.ExperimentalTypeInference 8 | import kotlin.jvm.JvmName 9 | 10 | @UnsafeNonEmptyCollectionApi 11 | inline fun NonEmptyCollection.wrapOperator( 12 | operator: Iterable.() -> List, 13 | ): NonEmptyList = wrapOperator(Unit, operator.addUnitParameter()) 14 | 15 | @UnsafeNonEmptyCollectionApi 16 | inline fun NonEmptyCollection.wrapOperator( 17 | parameter: Parameter, 18 | operator: Iterable.(Parameter) -> List 19 | ): NonEmptyList = wrapOperator(parameter, Unit, operator.addUnitParameter()) 20 | 21 | @UnsafeNonEmptyCollectionApi 22 | inline fun 23 | NonEmptyCollection.wrapOperator( 24 | firstParameter: FirstParameter, 25 | secondParameter: SecondParameter, 26 | operator: Iterable.(FirstParameter, SecondParameter) -> List 27 | ): NonEmptyList = operator(firstParameter, secondParameter).toNonEmptyList() 28 | 29 | @JvmName("wrapListOperator") 30 | @UnsafeNonEmptyCollectionApi 31 | inline fun NonEmptyCollection.wrapOperator( 32 | operator: List.() -> List, 33 | ): NonEmptyList = wrapOperator(Unit, operator.addUnitParameter()) 34 | 35 | @JvmName("wrapListOperator") 36 | @UnsafeNonEmptyCollectionApi 37 | inline fun NonEmptyCollection.wrapOperator( 38 | parameter: Parameter, 39 | operator: List.(Parameter) -> List 40 | ): NonEmptyList = wrapOperator(parameter, Unit, operator.addUnitParameter()) 41 | 42 | @JvmName("wrapListOperator") 43 | @UnsafeNonEmptyCollectionApi 44 | inline fun 45 | NonEmptyCollection.wrapOperator( 46 | firstParameter: FirstParameter, 47 | secondParameter: SecondParameter, 48 | operator: List.(FirstParameter, SecondParameter) -> List 49 | ): NonEmptyList = toList().operator(firstParameter, secondParameter).toNonEmptyList() 50 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/unsafe/wrapMapOperator.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(ExperimentalTypeInference::class) 2 | 3 | package com.quickbirdstudios.nonEmptyCollection.unsafe 4 | 5 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 6 | import com.quickbirdstudios.nonEmptyCollection.list.NonEmptyList 7 | import com.quickbirdstudios.nonEmptyCollection.map.NonEmptyMap 8 | import kotlin.experimental.ExperimentalTypeInference 9 | 10 | @UnsafeNonEmptyCollectionApi 11 | inline fun NonEmptyCollection.wrapOperator( 12 | operator: Iterable.() -> Map 13 | ): NonEmptyMap = wrapOperator(Unit, operator.addUnitParameter()) 14 | 15 | @UnsafeNonEmptyCollectionApi 16 | inline fun NonEmptyCollection.wrapOperator( 17 | parameter: Parameter, 18 | operator: Iterable.(Parameter) -> Map 19 | ): NonEmptyMap = wrapOperator(parameter, Unit, operator.addUnitParameter()) 20 | 21 | @UnsafeNonEmptyCollectionApi 22 | inline fun 23 | NonEmptyCollection.wrapOperator( 24 | firstParameter: FirstParameter, 25 | secondParameter: SecondParameter, 26 | operator: Iterable.(FirstParameter, SecondParameter) -> Map 27 | ): NonEmptyMap = operator(firstParameter, secondParameter).toNonEmptyMap() 28 | 29 | @UnsafeNonEmptyCollectionApi 30 | inline fun 31 | NonEmptyMap.wrapOperator( 32 | operator: Map.() -> Map 33 | ): NonEmptyMap = wrapOperator(Unit, operator.addUnitParameter()) 34 | 35 | @UnsafeNonEmptyCollectionApi 36 | inline fun 37 | NonEmptyMap.wrapOperator( 38 | parameter: Parameter, 39 | operator: Map.(Parameter) -> Map 40 | ): NonEmptyMap = wrapOperator(parameter, Unit, operator.addUnitParameter()) 41 | 42 | @UnsafeNonEmptyCollectionApi 43 | inline fun 44 | NonEmptyMap.wrapOperator( 45 | firstParameter: FirstParameter, 46 | secondParameter: SecondParameter, 47 | operator: Map.( 48 | FirstParameter, SecondParameter 49 | ) -> Map 50 | ): NonEmptyMap = operator(firstParameter, secondParameter).toNonEmptyMap() 51 | 52 | @UnsafeNonEmptyCollectionApi 53 | inline fun NonEmptyMap.wrapOperator( 54 | operator: Map.() -> Iterable 55 | ): NonEmptyList = wrapOperator(Unit, operator.addUnitParameter()) 56 | 57 | @UnsafeNonEmptyCollectionApi 58 | inline fun NonEmptyMap.wrapOperator( 59 | parameter: Parameter, 60 | operator: Map.(Parameter) -> Iterable 61 | ): NonEmptyList = wrapOperator(parameter, Unit, operator.addUnitParameter()) 62 | 63 | @UnsafeNonEmptyCollectionApi 64 | inline fun 65 | NonEmptyMap.wrapOperator( 66 | firstParameter: FirstParameter, 67 | secondParameter: SecondParameter, 68 | operator: Map.(FirstParameter, SecondParameter) -> Iterable 69 | ): NonEmptyList = operator(firstParameter, secondParameter).toNonEmptyList() 70 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/quickbirdstudios/nonEmptyCollection/unsafe/wrapSetOperator.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(ExperimentalTypeInference::class) 2 | 3 | package com.quickbirdstudios.nonEmptyCollection.unsafe 4 | 5 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 6 | import com.quickbirdstudios.nonEmptyCollection.set.NonEmptySet 7 | import kotlin.experimental.ExperimentalTypeInference 8 | import kotlin.jvm.JvmName 9 | 10 | @UnsafeNonEmptyCollectionApi 11 | inline fun NonEmptyCollection.wrapOperator( 12 | operator: Iterable.() -> Set, 13 | ): NonEmptySet = wrapOperator(Unit, operator.addUnitParameter()) 14 | 15 | @UnsafeNonEmptyCollectionApi 16 | inline fun NonEmptyCollection.wrapOperator( 17 | parameter: Parameter, 18 | operator: Iterable.(Parameter) -> Set 19 | ): NonEmptySet = wrapOperator(parameter, Unit, operator.addUnitParameter()) 20 | 21 | @UnsafeNonEmptyCollectionApi 22 | inline fun 23 | NonEmptyCollection.wrapOperator( 24 | firstParameter: FirstParameter, 25 | secondParameter: SecondParameter, 26 | operator: Iterable.(FirstParameter, SecondParameter) -> Set 27 | ): NonEmptySet = operator(firstParameter, secondParameter).toNonEmptySet() 28 | 29 | @JvmName("wrapSetOperator") 30 | @UnsafeNonEmptyCollectionApi 31 | inline fun NonEmptyCollection.wrapOperator( 32 | operator: Set.() -> Set, 33 | ): NonEmptySet = wrapOperator(Unit, operator.addUnitParameter()) 34 | 35 | @JvmName("wrapSetOperator") 36 | @UnsafeNonEmptyCollectionApi 37 | inline fun NonEmptyCollection.wrapOperator( 38 | parameter: Parameter, 39 | operator: Set.(Parameter) -> Set 40 | ): NonEmptySet = wrapOperator(parameter, Unit, operator.addUnitParameter()) 41 | 42 | @JvmName("wrapSetOperator") 43 | @UnsafeNonEmptyCollectionApi 44 | inline fun 45 | NonEmptyCollection.wrapOperator( 46 | firstParameter: FirstParameter, 47 | secondParameter: SecondParameter, 48 | operator: Set.(FirstParameter, SecondParameter) -> Set 49 | ): NonEmptySet = toSet().operator(firstParameter, secondParameter).toNonEmptySet() 50 | -------------------------------------------------------------------------------- /src/jvmMain/kotlin/com/quickbirdstudios/nonEmptyCollection/NonEmptyCollection+shuffled.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(UnsafeNonEmptyCollectionApi::class) 2 | @file:Suppress("unused") 3 | 4 | package com.quickbirdstudios.nonEmptyCollection 5 | 6 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 7 | import com.quickbirdstudios.nonEmptyCollection.unsafe.wrapOperator 8 | import java.util.* 9 | 10 | fun NonEmptyCollection.shuffled() = wrapOperator(Iterable::shuffled) 11 | 12 | fun NonEmptyCollection.shuffled(random: Random) = wrapOperator(random, Iterable::shuffled) 13 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/NonEmptyCollectionsOperatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection 2 | 3 | import kotlin.test.Test 4 | 5 | class NonEmptyCollectionsOperatorTest { 6 | 7 | @Test 8 | fun min() { 9 | assertOperationEquals( 10 | Iterable::minOrNull, 11 | NonEmptyCollection::min, 12 | 0f, 12f, 430f, 6969f, -8978f 13 | ) 14 | 15 | assertOperationEquals( 16 | Iterable::minOrNull, 17 | NonEmptyCollection::min, 18 | 0.9, 123.9, 12.3, 69.89, -56.8, -57.9 19 | ) 20 | 21 | assertOperationEquals( 22 | Iterable::minOrNull, 23 | NonEmptyCollection::min, 24 | "Stefan", "Klaus", "Mischa", "Malte", "Nasir", "Frederik" 25 | ) 26 | } 27 | 28 | @Test 29 | fun max() { 30 | assertOperationEquals( 31 | Iterable::maxOrNull, 32 | NonEmptyCollection::max, 33 | 0f, 12f, 430f, 6969f, -8978f 34 | ) 35 | 36 | assertOperationEquals( 37 | Iterable::maxOrNull, 38 | NonEmptyCollection::max, 39 | 0.9, 123.9, 12.3, 69.89, -56.8, -57.9 40 | ) 41 | 42 | assertOperationEquals( 43 | Iterable::maxOrNull, 44 | NonEmptyCollection::max, 45 | "Stefan", "Klaus", "Mischa", "Malte", "Nasir", "Frederik" 46 | ) 47 | } 48 | 49 | @Test 50 | fun minBy() { 51 | assertOperationEquals( 52 | Iterable::minByOrNull, 53 | NonEmptyCollection::minBy, 54 | { value -> -value * 2 }, 55 | 0f, 12f, 430f, 6969f, -8978f 56 | ) 57 | 58 | assertOperationEquals( 59 | Iterable::minByOrNull, 60 | NonEmptyCollection::minBy, 61 | { value -> -value * 42.69 }, 62 | 0.9, 123.9, 12.3, 69.89, -56.8, -57.9 63 | ) 64 | 65 | assertOperationEquals( 66 | Iterable::minByOrNull, 67 | NonEmptyCollection::minBy, 68 | { value -> value.length }, 69 | "Stefan", "Klaus", "Mischa", "Malte", "Nasir", "Frederik" 70 | ) 71 | } 72 | 73 | @Test 74 | fun maxBy() { 75 | assertOperationEquals( 76 | Iterable::maxByOrNull, 77 | NonEmptyCollection::maxBy, 78 | { value -> -value * 2 }, 79 | 0f, 12f, 430f, 6969f, -8978f 80 | ) 81 | 82 | assertOperationEquals( 83 | Iterable::maxByOrNull, 84 | NonEmptyCollection::maxBy, 85 | { value -> -value * 42.69 }, 86 | 0.9, 123.9, 12.3, 69.89, -56.8, -57.9 87 | ) 88 | 89 | assertOperationEquals( 90 | Iterable::maxByOrNull, 91 | NonEmptyCollection::maxBy, 92 | { value -> value.length }, 93 | "Stefan", "Klaus", "Mischa", "Malte", "Nasir", "Frederik" 94 | ) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/ToNonEmptyOrNullTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | import kotlin.test.assertNull 6 | 7 | class ToNonEmptyOrNullTest { 8 | @Test 9 | fun toNonEmptyOrNull_null() { 10 | val list = listOf() 11 | val set = setOf() 12 | val map = mapOf() 13 | 14 | assertNull(list.toNonEmptyListOrNull()) 15 | assertNull(set.toNonEmptyMapOrNull()) 16 | assertNull(map.toNonEmptyMapOrNull()) 17 | } 18 | 19 | @Test 20 | fun toNonEmptyOrNull_not_null() { 21 | val list = listOf(33, 44, 34543, -99) 22 | val set = setOf(-23, 34, 4) 23 | val map = mapOf(69 to "430", -12 to "Hallo") 24 | 25 | assertEquals?>(list, list.toNonEmptyListOrNull()) 26 | assertEquals?>(set, set.toNonEmptyMapOrNull()) 27 | assertEquals?>(map, map.toNonEmptyMapOrNull()) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/ToNonEmptyOrTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.list.nonEmptyListOf 4 | import com.quickbirdstudios.nonEmptyCollection.map.nonEmptyMapOf 5 | import com.quickbirdstudios.nonEmptyCollection.set.nonEmptySetOf 6 | import kotlin.test.Test 7 | import kotlin.test.assertEquals 8 | 9 | class ToNonEmptyOrTest { 10 | @Test 11 | fun toNonEmptyOr_alternative() { 12 | val alternativeList = nonEmptyListOf(1, 2, 4) 13 | val list = listOf() 14 | 15 | val alternativeSet = nonEmptySetOf(1, 2, 4) 16 | val set = setOf() 17 | 18 | val alternativeMap = nonEmptyMapOf(1 to "3", 2 to "rrr", 4 to "sfgfdgdf") 19 | val map = mapOf() 20 | 21 | assertEquals(alternativeList, list.toNonEmptyListOr { alternativeList }) 22 | assertEquals(alternativeSet, set.toNonEmptySetOr { alternativeSet }) 23 | assertEquals(alternativeMap, map.toNonEmptyMapOr { alternativeMap }) 24 | } 25 | 26 | @Test 27 | fun toNonEmptyOr_notAlternative() { 28 | val alternativeList = nonEmptyListOf(1, 2, 4) 29 | val list = listOf(45, 54, 666) 30 | 31 | val alternativeSet = nonEmptySetOf(1, 2, 4) 32 | val set = setOf(-5656, 555, 4949, 99) 33 | 34 | val alternativeMap = nonEmptyMapOf(1 to "3", 2 to "rrr", 4 to "sfgfdgdf") 35 | val map = mapOf(69 to "420") 36 | 37 | assertEquals(list, list.toNonEmptyListOr { alternativeList }) 38 | assertEquals(set, set.toNonEmptySetOr { alternativeSet }) 39 | assertEquals(map, map.toNonEmptyMapOr { alternativeMap }) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/assertOperationEquals.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.list.nonEmptyListOf 4 | import com.quickbirdstudios.nonEmptyCollection.unsafe.addUnitParameter 5 | import kotlin.test.assertEquals 6 | 7 | fun assertOperationEquals( 8 | expected: Iterable.() -> R, 9 | actual: NonEmptyCollection.() -> R, 10 | element: T, 11 | vararg elements: T 12 | ) = assertOperationEquals( 13 | expected = expected.addUnitParameter(), 14 | actual = actual.addUnitParameter(), 15 | parameter = Unit, 16 | element = element, 17 | elements = elements 18 | ) 19 | 20 | fun assertOperationEquals( 21 | expected: Iterable.(P) -> R, 22 | actual: NonEmptyCollection.(P) -> R, 23 | parameter: P, 24 | element: T, 25 | vararg elements: T 26 | ) = assertOperationEquals( 27 | expected = expected.addUnitParameter(), 28 | actual = actual.addUnitParameter(), 29 | parameter1 = parameter, 30 | parameter2 = Unit, 31 | element = element, 32 | elements = elements 33 | ) 34 | 35 | fun assertOperationEquals( 36 | expected: Iterable.(P1, P2) -> R, 37 | actual: NonEmptyCollection.(P1, P2) -> R, 38 | parameter1: P1, 39 | parameter2: P2, 40 | element: T, 41 | vararg elements: T 42 | ) { 43 | val list = listOf(element, *elements) 44 | val nonEmptyList = nonEmptyListOf(element, *elements) 45 | 46 | assertEquals(list.expected(parameter1, parameter2), nonEmptyList.actual(parameter1, parameter2)) 47 | } 48 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/assertThrows.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection 2 | 3 | import kotlin.test.assertTrue 4 | 5 | inline fun assertThrows(action: () -> Unit) { 6 | var thrown = false 7 | try { 8 | action() 9 | } catch (caught: Throwable) { 10 | if (T::class.isInstance(caught)) { 11 | thrown = true 12 | } 13 | } 14 | 15 | assertTrue(thrown) 16 | } 17 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/list/NonEmptyListOfTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.list 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | import kotlin.test.assertNotEquals 6 | 7 | class NonEmptyListOfTest { 8 | @Test 9 | fun nonEmptyListOf() { 10 | assertEquals(listOf(-12, -454, 56), nonEmptyListOf(-12, -454, 56)) 11 | assertNotEquals(listOf(-12, -454, 56), nonEmptyListOf(-12, -454, 55)) 12 | 13 | assertEquals(listOf(-12, -454, 56), nonEmptyListOf(-12, listOf(-454, 56))) 14 | assertNotEquals(listOf(-12, -454, 56), nonEmptyListOf(-12, listOf(-454, 55))) 15 | } 16 | 17 | @Test 18 | fun nonEmptyListOfNotNull() { 19 | assertEquals(listOf(-12, -454, 56), nonEmptyListOfNotNull(-12, -454, 56)) 20 | assertNotEquals(listOf(-12, -454, 56), nonEmptyListOfNotNull(-12, -454, 55)) 21 | 22 | assertEquals(listOf(-12, -454, 56), nonEmptyListOfNotNull(-12, listOf(-454, 56))) 23 | assertNotEquals(listOf(-12, -454, 56), nonEmptyListOfNotNull(-12, listOf(-454, 55))) 24 | 25 | assertEquals(listOf(-12, -454, 56), nonEmptyListOfNotNull(-12, -454, 56, null)) 26 | assertNotEquals(listOf(-12, -454, 56), nonEmptyListOfNotNull(-12, null, -454, 55)) 27 | 28 | assertEquals( 29 | listOf(-12, -454, 56), 30 | nonEmptyListOfNotNull(-12, listOf(-454, 56, null, null)) 31 | ) 32 | assertNotEquals( 33 | listOf(-12, -454, 56), 34 | nonEmptyListOfNotNull(-12, listOf(null, null, -454, 55)) 35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/list/NonEmptyListOperatorsTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.list 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 4 | import com.quickbirdstudios.nonEmptyCollection.assertOperationEquals 5 | import com.quickbirdstudios.nonEmptyCollection.shuffled 6 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 7 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyList 8 | import kotlin.random.Random 9 | import kotlin.test.Test 10 | import kotlin.test.assertEquals 11 | 12 | class NonEmptyListOperatorsTest { 13 | @OptIn(UnsafeNonEmptyCollectionApi::class) 14 | @Test 15 | fun toNonEmptyList() { 16 | assertOperationEquals( 17 | Iterable::toNonEmptyList, 18 | NonEmptyCollection::toNonEmptyList, 19 | 23, 324334, -3434 20 | ) 21 | } 22 | 23 | @Test 24 | fun asReversed() { 25 | assertListOperationEquals( 26 | List::asReversed, 27 | NonEmptyList::asReversed, 28 | 23, 324334, -3434 29 | ) 30 | } 31 | 32 | @Test 33 | fun sorted() { 34 | assertOperationEquals( 35 | Iterable::sorted, 36 | NonEmptyCollection::sorted, 37 | 23, 324334, -3434, 7878, 234234 38 | ) 39 | } 40 | 41 | @Test 42 | fun sortedBy() { 43 | assertOperationEquals( 44 | Iterable::sortedBy, 45 | NonEmptyCollection::sortedBy, 46 | { value -> value.toDouble() * 42 - 5 }, 47 | 23, 324334, -3434, 7878, 234234 48 | ) 49 | } 50 | 51 | @Test 52 | fun sortedWith() { 53 | assertOperationEquals( 54 | Iterable::sortedWith, 55 | NonEmptyCollection::sortedWith, 56 | object : Comparator { 57 | override fun compare(first: String?, second: String?): Int { 58 | if (first == null || second == null) return 0 59 | return first.length.compareTo(second.length) 60 | } 61 | 62 | }, 63 | "d", "32", "3434", "Stefan", "2342344" 64 | ) 65 | } 66 | 67 | @Test 68 | fun sortedDescending() { 69 | assertOperationEquals( 70 | Iterable::sortedDescending, 71 | NonEmptyCollection::sortedDescending, 72 | "dffd", "324334", "3434", "Stefan", "234234" 73 | ) 74 | } 75 | 76 | @Test 77 | fun sortedByDescending() { 78 | assertOperationEquals( 79 | Iterable::sortedByDescending, 80 | NonEmptyCollection::sortedByDescending, 81 | { value -> value.toDouble() * 42 - 5 }, 82 | 23, 324334, -3434, 7878, 234234 83 | ) 84 | } 85 | 86 | @Test 87 | fun onEach() { 88 | val mutableList = mutableListOf() 89 | 90 | assertListOperationEquals( 91 | List::onEach, 92 | NonEmptyList::onEach, 93 | { mutableList.add(Unit) }, 94 | "dffd", "324334", "3434", "Stefan", "234234" 95 | ) 96 | assertEquals(10, mutableList.size) 97 | } 98 | 99 | @Test 100 | fun onEachIndexed() { 101 | val mutableList = mutableListOf() 102 | 103 | assertListOperationEquals( 104 | List::onEachIndexed, 105 | NonEmptyList::onEachIndexed, 106 | { index, _ -> mutableList.add(index) }, 107 | "dffd", "324334", "3434", "Stefan", "234234" 108 | ) 109 | assertEquals(10, mutableList.size) 110 | assertEquals(5, mutableList.distinct().size) 111 | } 112 | 113 | @Test 114 | fun map() { 115 | assertOperationEquals( 116 | Iterable::map, 117 | NonEmptyCollection::map, 118 | { value -> value + value }, 119 | "dffd", "324334", "3434", "Stefan", "234234" 120 | ) 121 | } 122 | 123 | @Test 124 | fun mapIndexed() { 125 | assertOperationEquals( 126 | Iterable::mapIndexed, 127 | NonEmptyCollection::mapIndexed, 128 | { index, value -> value + index }, 129 | "dffd", "324334", "3434", "Stefan", "234234" 130 | ) 131 | } 132 | 133 | @Test 134 | fun flatMap() { 135 | assertOperationEquals( 136 | Iterable::flatMap, 137 | NonEmptyCollection::flatMap, 138 | { value -> nonEmptyListOf(value, value) }, 139 | "dffd", "324334", "3434", "Stefan", "234234" 140 | ) 141 | } 142 | 143 | @Test 144 | fun flatMapIndexed() { 145 | assertOperationEquals( 146 | Iterable::flatMapIndexed, 147 | NonEmptyCollection::flatMapIndexed, 148 | { index, _ -> nonEmptyListOf(index * 2) }, 149 | "dffd", "324334", "3434", "Stefan", "234234" 150 | ) 151 | } 152 | 153 | @Test 154 | fun scan() { 155 | assertOperationEquals( 156 | Iterable::scan, 157 | NonEmptyCollection::scan, 158 | "", 159 | { acc, value -> acc + value + value }, 160 | "dffd", "324334", "3434", "Stefan", "234234" 161 | ) 162 | } 163 | 164 | @Test 165 | fun scanIndexed() { 166 | assertOperationEquals( 167 | Iterable::scanIndexed, 168 | NonEmptyCollection::scanIndexed, 169 | "", 170 | { index, acc, value -> acc + value + value + index }, 171 | "dffd", "324334", "3434", "Stefan", "234234" 172 | ) 173 | } 174 | 175 | @Test 176 | fun runningReduce() { 177 | assertOperationEquals( 178 | Iterable::runningReduce, 179 | NonEmptyCollection::runningReduce, 180 | { acc, value -> acc + value + value }, 181 | -22.0, 420.0, 69.0, 69.69, 69.0 182 | ) 183 | } 184 | 185 | @Test 186 | fun runningReduceIndexed() { 187 | assertOperationEquals( 188 | Iterable::runningReduceIndexed, 189 | NonEmptyCollection::runningReduceIndexed, 190 | { index, acc, value -> acc + value + value + index }, 191 | -22.0, 420.0, 69.0, 69.69, 69.0 192 | ) 193 | } 194 | 195 | @Test 196 | fun runningFold() { 197 | assertOperationEquals( 198 | Iterable::runningFold, 199 | NonEmptyCollection::runningFold, 200 | 32.0, 201 | { acc, value -> acc + value + value }, 202 | -22.0, 420.0, 69.0, 69.69, 69.0 203 | ) 204 | } 205 | 206 | @Test 207 | fun runningFoldIndexed() { 208 | assertOperationEquals( 209 | Iterable::runningFoldIndexed, 210 | NonEmptyCollection::runningFoldIndexed, 211 | 32.0, 212 | { index, acc, value -> acc + value + value + index }, 213 | -22.0, 420.0, 69.0, 69.69, 69.0 214 | ) 215 | } 216 | 217 | @Test 218 | fun flatten() { 219 | assertOperationEquals( 220 | Iterable>::flatten, 221 | NonEmptyCollection>::flatten, 222 | nonEmptyListOf(-22.0, 420.0, 69.0), nonEmptyListOf(69.69, 69.0) 223 | ) 224 | } 225 | 226 | @Test 227 | fun reversed() { 228 | assertOperationEquals( 229 | Iterable>::reversed, 230 | NonEmptyCollection>::reversed, 231 | nonEmptyListOf(-22.0, 420.0, 69.0), nonEmptyListOf(69.69, 69.0) 232 | ) 233 | } 234 | 235 | @Test 236 | fun zip() { 237 | assertOperationEquals( 238 | Iterable::zip, 239 | NonEmptyCollection::zip, 240 | nonEmptyListOf(-22.0, 420.0, 69.0), 241 | 69.69, 69.0 242 | ) 243 | } 244 | 245 | @Test 246 | fun chunked() { 247 | assertOperationEquals( 248 | Iterable::chunked, 249 | NonEmptyCollection::chunked, 250 | 2, 251 | -22.0, 420.0, 69.0, 69.69, 69.0 252 | ) 253 | } 254 | 255 | @Test 256 | fun chunked_withTransformation() { 257 | assertOperationEquals( 258 | expected = Iterable::chunked, 259 | actual = NonEmptyCollection::chunked, 260 | parameter1 = 2, 261 | parameter2 = { list: List -> list.size }, 262 | -22.0, 420.0, 69.0, 69.69, 69.0 263 | ) 264 | } 265 | 266 | @Test 267 | fun withIndex() { 268 | val withIndexToList = fun Iterable.() = withIndex().toList() 269 | 270 | assertListOperationEquals( 271 | withIndexToList, 272 | NonEmptyList::withIndex, 273 | -22.0, 420.0, 69.0, 69.69, 69.0 274 | ) 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/list/NonEmptyListPlusTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.list 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class NonEmptyListPlusTest { 7 | 8 | @Test 9 | fun plusValue() { 10 | assertEquals( 11 | nonEmptyListOf(1, 2, 3), 12 | nonEmptyListOf(1, 2) + 3 13 | ) 14 | assertEquals( 15 | nonEmptyListOf(1, 2, 3), 16 | listOf(1, 2) + 3 17 | ) 18 | } 19 | 20 | @Test 21 | fun plusValues() { 22 | assertEquals( 23 | nonEmptyListOf(12, 22, 33, 43), 24 | nonEmptyListOf(12, 22) + listOf(33, 43) 25 | ) 26 | assertEquals( 27 | nonEmptyListOf(12, 22, 33, 43), 28 | listOf(12, 22) + nonEmptyListOf(33, 43) 29 | ) 30 | assertEquals( 31 | nonEmptyListOf(12, 22, 33, 43), 32 | nonEmptyListOf(12, 22) + nonEmptyListOf(33, 43) 33 | ) 34 | assertEquals( 35 | nonEmptyListOf(12, 22, 33, 43), 36 | nonEmptyListOf(12, 22) + (listOf(33, 43) as Iterable) 37 | ) 38 | assertEquals( 39 | nonEmptyListOf(12, 22, 33, 43), 40 | nonEmptyListOf(12, 22) + sequenceOf(33, 43) 41 | ) 42 | assertEquals( 43 | nonEmptyListOf(12, 22, 33, 43), 44 | nonEmptyListOf(12, 22) + arrayOf(33, 43) 45 | ) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/list/NonEmptyListTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.list 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | import kotlin.test.assertFalse 6 | import kotlin.test.assertNotEquals 7 | import kotlin.test.assertTrue 8 | 9 | class NonEmptyListTest { 10 | @Test 11 | fun equals() { 12 | assertTrue { NonEmptyList("f", listOf("ff", "fff")) == listOf("f", "ff", "fff") } 13 | assertFalse { NonEmptyList("f", listOf("ff", "fff")) == listOf("ff", "fff") } 14 | } 15 | 16 | @Test 17 | fun hashCodes() { 18 | assertEquals( 19 | listOf("f", "ff", "fff").hashCode(), 20 | NonEmptyList("f", listOf("ff", "fff")).hashCode() 21 | ) 22 | assertNotEquals( 23 | listOf("f", "ff", "fff").hashCode(), 24 | NonEmptyList("f", listOf("ff", "eff")).hashCode() 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/list/assertListOperationEquals.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.list 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.assertOperationEquals 4 | 5 | fun assertListOperationEquals( 6 | expected: List.() -> R, 7 | actual: NonEmptyList.() -> R, 8 | element: T, 9 | vararg elements: T 10 | ) = assertOperationEquals( 11 | expected = { toList().expected() }, 12 | actual = { toNonEmptyList().actual() }, 13 | element = element, 14 | elements = elements 15 | ) 16 | 17 | fun assertListOperationEquals( 18 | expected: List.(P) -> R, 19 | actual: NonEmptyList.(P) -> R, 20 | parameter: P, 21 | element: T, 22 | vararg elements: T 23 | ) = assertOperationEquals( 24 | expected = { p -> toList().expected(p) }, 25 | actual = { p -> toNonEmptyList().actual(p) }, 26 | parameter = parameter, 27 | element = element, 28 | elements = elements 29 | ) 30 | 31 | fun assertListOperationEquals( 32 | expected: List.(P1, P2) -> R, 33 | actual: NonEmptyList.(P1, P2) -> R, 34 | parameter1: P1, 35 | parameter2: P2, 36 | element: T, 37 | vararg elements: T 38 | ) = assertOperationEquals( 39 | expected = { p1, p2 -> toList().expected(p1, p2) }, 40 | actual = { p1, p2 -> toNonEmptyList().actual(p1, p2) }, 41 | parameter1 = parameter1, 42 | parameter2 = parameter2, 43 | element = element, 44 | elements = elements 45 | ) 46 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/map/NonEmptyMapOfTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.map 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | import kotlin.test.assertNotEquals 6 | 7 | class NonEmptyMapOfTest { 8 | @Test 9 | fun nonEmptyListOf() { 10 | assertEquals( 11 | mapOf(-12 to "1", -454 to "b", 56 to "c"), 12 | nonEmptyMapOf(-12 to "1", -454 to "b", 56 to "c") 13 | ) 14 | assertNotEquals( 15 | mapOf(-12 to "1", -454 to "b", 56 to "c"), 16 | nonEmptyMapOf(-12 to "1", -454 to "a", 56 to "c") 17 | ) 18 | 19 | assertEquals( 20 | mapOf(-12 to "1", -454 to "b", 56 to "c"), 21 | nonEmptyMapOf(-12 to "1", mapOf(-454 to "b", 56 to "c")) 22 | ) 23 | assertNotEquals( 24 | mapOf(-12 to "1", -454 to "b", 56 to "c"), 25 | nonEmptyMapOf(-12 to "1", mapOf(-44 to "b", 56 to "c")) 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/map/NonEmptyMapOperatorsTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.map 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 4 | import com.quickbirdstudios.nonEmptyCollection.assertOperationEquals 5 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 6 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyMap 7 | import kotlin.test.Test 8 | import kotlin.test.assertEquals 9 | 10 | class NonEmptyMapOperatorsTest { 11 | @OptIn(UnsafeNonEmptyCollectionApi::class) 12 | @Test 13 | fun toNonEmptyMap() { 14 | assertOperationEquals( 15 | Iterable>::toNonEmptyMap, 16 | NonEmptyCollection>::toNonEmptyMap, 17 | 23 to '8', 324334 to 'h', -3434 to 'k' 18 | ) 19 | } 20 | 21 | @Test 22 | fun onEach() { 23 | val mutableMap = mutableMapOf() 24 | 25 | assertMapOperationEquals( 26 | Map::onEach, 27 | NonEmptyMap::onEach, 28 | { entry -> mutableMap[entry.value] = Unit }, 29 | "dffd" to 1, "324334" to 2, "3434" to 3, "Stefan" to 4, "234234" to 17 30 | ) 31 | assertEquals(5, mutableMap.size) 32 | } 33 | 34 | @Test 35 | fun onEachIndexed() { 36 | val mutableMap = mutableMapOf() 37 | 38 | assertMapOperationEquals( 39 | Map::onEachIndexed, 40 | NonEmptyMap::onEachIndexed, 41 | { index, entry -> mutableMap[entry.value] = index }, 42 | "dffd" to 1, "324334" to 2, "3434" to 3, "Stefan" to 4, "234234" to 17 43 | ) 44 | assertEquals(5, mutableMap.size) 45 | } 46 | 47 | @Test 48 | fun associate() { 49 | assertOperationEquals( 50 | Iterable::associate, 51 | NonEmptyCollection::associate, 52 | { value -> value to value.length }, 53 | "dffd", "324334", "3434", "Stefan", "234234" 54 | ) 55 | } 56 | 57 | @Test 58 | fun associateWith() { 59 | assertOperationEquals( 60 | Iterable::associateWith, 61 | NonEmptyCollection::associateWith, 62 | { value -> value.length }, 63 | "dffd", "324334", "3434", "Stefan", "234234" 64 | ) 65 | } 66 | 67 | @Test 68 | fun associateBy() { 69 | assertOperationEquals( 70 | Iterable::associateBy, 71 | NonEmptyCollection::associateBy, 72 | { value -> value.length }, 73 | "dffd", "324334", "3434", "Stefan", "234234" 74 | ) 75 | } 76 | 77 | @Test 78 | fun mapValues() { 79 | assertMapOperationEquals( 80 | Map::mapValues, 81 | NonEmptyMap::mapValues, 82 | { entry -> entry.value * 2 }, 83 | "dffd" to 10, "324334" to 455, "3434" to 69, "Stefan" to 9, "234234" to 0 84 | ) 85 | } 86 | 87 | @Test 88 | fun mapKeys() { 89 | assertMapOperationEquals( 90 | Map::mapKeys, 91 | NonEmptyMap::mapKeys, 92 | { entry -> entry.value * 4 }, 93 | "dffd" to 10, "324334" to 455, "3434" to 69, "Stefan" to 9, "234234" to 0 94 | ) 95 | } 96 | 97 | @Test 98 | fun maxBy() { 99 | assertMapOperationEquals( 100 | Map::maxByOrNull, 101 | NonEmptyMap::maxBy, 102 | { entry -> entry.value * 14 }, 103 | "dffd" to 10, "324334" to 455, "3434" to 69, "Stefan" to 9, "234234" to 0 104 | ) 105 | } 106 | 107 | @Test 108 | fun map() { 109 | assertMapOperationEquals( 110 | Map::minByOrNull, 111 | NonEmptyMap::minBy, 112 | { entry -> entry.key }, 113 | "dffd" to 10, "324334" to 455, "3434" to 69, "Stefan" to 9, "234234" to 0 114 | ) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/map/NonEmptyMapPlusTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.map 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class NonEmptyMapPlusTest { 7 | 8 | @Test 9 | fun plusValue() { 10 | assertEquals( 11 | nonEmptyMapOf(1 to 'a', 2 to 'b', 3 to 'c'), 12 | nonEmptyMapOf(1 to 'a', 2 to 'b') + (3 to 'c') 13 | ) 14 | assertEquals>( 15 | nonEmptyMapOf(1 to 'a', 2 to 'b', 3 to 'c'), 16 | mapOf(1 to 'a', 2 to 'b') + (3 to 'c') 17 | ) 18 | } 19 | 20 | @Test 21 | fun plusValues() { 22 | assertEquals( 23 | nonEmptyMapOf(1 to 'a', 2 to 'b', 3 to 'c', 4 to 'd'), 24 | nonEmptyMapOf(1 to 'a', 2 to 'b') + mapOf(3 to 'c', 4 to 'd') 25 | ) 26 | assertEquals>( 27 | nonEmptyMapOf(1 to 'a', 2 to 'b', 3 to 'c', 4 to 'd'), 28 | mapOf(1 to 'a', 2 to 'b') + nonEmptyMapOf(3 to 'c', 4 to 'd') 29 | ) 30 | assertEquals( 31 | nonEmptyMapOf(1 to 'a', 2 to 'b', 3 to 'c', 4 to 'd'), 32 | nonEmptyMapOf(1 to 'a', 2 to 'b') + nonEmptyMapOf(3 to 'c', 4 to 'd') 33 | ) 34 | assertEquals( 35 | nonEmptyMapOf(1 to 'a', 2 to 'b', 3 to 'c', 4 to 'd'), 36 | nonEmptyMapOf(1 to 'a', 2 to 'b') + listOf(3 to 'c', 4 to 'd') 37 | ) 38 | assertEquals( 39 | nonEmptyMapOf(1 to 'a', 2 to 'b', 3 to 'c', 4 to 'd'), 40 | nonEmptyMapOf(1 to 'a', 2 to 'b') + sequenceOf(3 to 'c', 4 to 'd') 41 | ) 42 | assertEquals( 43 | nonEmptyMapOf(1 to 'a', 2 to 'b', 3 to 'c', 4 to 'd'), 44 | nonEmptyMapOf(1 to 'a', 2 to 'b') + arrayOf(3 to 'c', 4 to 'd') 45 | ) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/map/NonEmptyMapTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.map 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | import kotlin.test.assertFalse 6 | import kotlin.test.assertNotEquals 7 | import kotlin.test.assertTrue 8 | 9 | class NonEmptyMapTest { 10 | @Test 11 | fun equals() { 12 | assertTrue { 13 | NonEmptyMap("f" to 1, mapOf("ff" to 2, "fff" to 3)) == 14 | mapOf("f" to 1, "ff" to 2, "fff" to 3) 15 | } 16 | assertFalse { 17 | NonEmptyMap("f" to 1, mapOf("ff" to 2, "fff" to 3)) == 18 | mapOf("f" to 1, "ff" to 2, "fff" to 4) 19 | } 20 | } 21 | 22 | @Test 23 | fun hashCodes() { 24 | assertEquals( 25 | mapOf("f" to 1, "ff" to 2, "fff" to 3).hashCode(), 26 | NonEmptyMap("f" to 1, mapOf("ff" to 2, "fff" to 3)).hashCode() 27 | ) 28 | assertNotEquals( 29 | mapOf("f" to 1, "ff" to 2, "fff" to 3).hashCode(), 30 | NonEmptyMap("f" to 1, mapOf("ff" to 2, "ff" to 3)).hashCode() 31 | ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/map/assertMapOperationEquals.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.map 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.assertOperationEquals 4 | 5 | fun assertMapOperationEquals( 6 | expected: Map.() -> R, 7 | actual: NonEmptyMap.() -> R, 8 | element: Pair, 9 | vararg elements: Pair 10 | ) = assertOperationEquals( 11 | expected = { toMap().expected() }, 12 | actual = { toNonEmptyMap().actual() }, 13 | element = element, 14 | elements = elements 15 | ) 16 | 17 | fun assertMapOperationEquals( 18 | expected: Map.(P) -> R, 19 | actual: NonEmptyMap.(P) -> R, 20 | parameter: P, 21 | element: Pair, 22 | vararg elements: Pair 23 | ) = assertOperationEquals( 24 | expected = { p -> toMap().expected(p) }, 25 | actual = { p -> toNonEmptyMap().actual(p) }, 26 | parameter = parameter, 27 | element = element, 28 | elements = elements 29 | ) 30 | 31 | fun assertMapOperationEquals( 32 | expected: Map.(P1, P2) -> R, 33 | actual: NonEmptyMap.(P1, P2) -> R, 34 | parameter1: P1, 35 | parameter2: P2, 36 | element: Pair, 37 | vararg elements: Pair 38 | ) = assertOperationEquals( 39 | expected = { p1, p2 -> toMap().expected(p1, p2) }, 40 | actual = { p1, p2 -> toNonEmptyMap().actual(p1, p2) }, 41 | parameter1 = parameter1, 42 | parameter2 = parameter2, 43 | element = element, 44 | elements = elements 45 | ) 46 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/set/NonEmptySetOfTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.set 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | import kotlin.test.assertNotEquals 6 | 7 | class NonEmptySetOfTest { 8 | @Test 9 | fun nonEmptyListOf() { 10 | assertEquals(setOf(-12, -454, 56), nonEmptySetOf(-12, -454, 56)) 11 | assertNotEquals(setOf(-12, -454, 56), nonEmptySetOf(-12, -454, 55)) 12 | 13 | assertEquals(setOf(-12, -454, 56), nonEmptySetOf(-12, setOf(-454, 56))) 14 | assertNotEquals(setOf(-12, -454, 56), nonEmptySetOf(-12, setOf(-454, 55))) 15 | } 16 | 17 | @Test 18 | fun nonEmptyListOfNotNull() { 19 | assertEquals(setOf(-12, -454, 56), nonEmptySetOfNotNull(-12, -454, 56)) 20 | assertNotEquals(setOf(-12, -454, 56), nonEmptySetOfNotNull(-12, -454, 55)) 21 | 22 | assertEquals(setOf(-12, -454, 56), nonEmptySetOfNotNull(-12, setOf(-454, 56))) 23 | assertNotEquals(setOf(-12, -454, 56), nonEmptySetOfNotNull(-12, setOf(-454, 55))) 24 | 25 | assertEquals(setOf(-12, -454, 56), nonEmptySetOfNotNull(-12, -454, 56, null)) 26 | assertNotEquals(setOf(-12, -454, 56), nonEmptySetOfNotNull(-12, null, -454, 55)) 27 | 28 | assertEquals( 29 | setOf(-12, -454, 56), 30 | nonEmptySetOfNotNull(-12, setOf(-454, 56, null, null)) 31 | ) 32 | assertNotEquals( 33 | setOf(-12, -454, 56), 34 | nonEmptySetOfNotNull(-12, setOf(null, null, -454, 55)) 35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/set/NonEmptySetOperatorsTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.set 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.NonEmptyCollection 4 | import com.quickbirdstudios.nonEmptyCollection.assertOperationEquals 5 | import com.quickbirdstudios.nonEmptyCollection.unsafe.UnsafeNonEmptyCollectionApi 6 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptyList 7 | import com.quickbirdstudios.nonEmptyCollection.unsafe.toNonEmptySet 8 | import kotlin.test.Test 9 | import kotlin.test.assertEquals 10 | 11 | class NonEmptySetOperatorsTest { 12 | @OptIn(UnsafeNonEmptyCollectionApi::class) 13 | @Test 14 | fun toNonEmptySet() { 15 | assertOperationEquals( 16 | Iterable::toNonEmptySet, 17 | NonEmptyCollection::toNonEmptySet, 18 | 23, 324334, -3434 19 | ) 20 | } 21 | 22 | @Test 23 | fun onEach() { 24 | val mutableSet = mutableSetOf() 25 | 26 | assertSetOperationEquals( 27 | Set::onEach, 28 | NonEmptySet::onEach, 29 | { value -> mutableSet.add(value) }, 30 | "dffd", "324334", "3434", "Stefan", "234234" 31 | ) 32 | assertEquals(5, mutableSet.size) 33 | } 34 | 35 | @Test 36 | fun onEachIndexed() { 37 | val mutableSet = mutableSetOf() 38 | 39 | assertSetOperationEquals( 40 | Set::onEachIndexed, 41 | NonEmptySet::onEachIndexed, 42 | { index, _ -> mutableSet.add(index) }, 43 | "dffd", "324334", "3434", "Stefan", "234234" 44 | ) 45 | assertEquals(5, mutableSet.size) 46 | } 47 | 48 | @Test 49 | fun union() { 50 | assertOperationEquals( 51 | Iterable::union, 52 | NonEmptyCollection::union, 53 | listOf("dffd", "324334"), 54 | "3434", "Stefan", "234234" 55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/set/NonEmptySetPlusTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.set 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class NonEmptySetPlusTest { 7 | 8 | @Test 9 | fun plusValue() { 10 | assertEquals( 11 | nonEmptySetOf(1, 2, 3), 12 | nonEmptySetOf(1, 2) + 3 13 | ) 14 | assertEquals( 15 | nonEmptySetOf(1, 2, 3), 16 | setOf(1, 2) + 3 17 | ) 18 | } 19 | 20 | @Test 21 | fun plusValues() { 22 | assertEquals( 23 | nonEmptySetOf(12, 22, 33, 43), 24 | nonEmptySetOf(12, 22) + setOf(33, 43) 25 | ) 26 | assertEquals( 27 | nonEmptySetOf(12, 22, 33, 43), 28 | setOf(12, 22) + nonEmptySetOf(33, 43) 29 | ) 30 | assertEquals( 31 | nonEmptySetOf(12, 22, 33, 43), 32 | nonEmptySetOf(12, 22) + nonEmptySetOf(33, 43) 33 | ) 34 | assertEquals( 35 | nonEmptySetOf(12, 22, 33, 43), 36 | nonEmptySetOf(12, 22) + (setOf(33, 43) as Iterable) 37 | ) 38 | assertEquals( 39 | nonEmptySetOf(12, 22, 33, 43), 40 | nonEmptySetOf(12, 22) + sequenceOf(33, 43) 41 | ) 42 | assertEquals( 43 | nonEmptySetOf(12, 22, 33, 43), 44 | nonEmptySetOf(12, 22) + arrayOf(33, 43) 45 | ) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/set/NonEmptySetTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.set 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | import kotlin.test.assertFalse 6 | import kotlin.test.assertNotEquals 7 | import kotlin.test.assertTrue 8 | 9 | class NonEmptySetTest { 10 | @Test 11 | fun equals() { 12 | assertTrue { NonEmptySet("f", setOf("ff", "fff")) == setOf("f", "ff", "fff") } 13 | assertFalse { NonEmptySet("f", setOf("ff", "fff")) == setOf("ff", "fff") } 14 | } 15 | 16 | @Test 17 | fun hashCodes() { 18 | assertEquals( 19 | setOf("f", "ff", "fff").hashCode(), 20 | NonEmptySet("f", setOf("ff", "fff")).hashCode() 21 | ) 22 | assertNotEquals( 23 | setOf("f", "ff", "fff").hashCode(), 24 | NonEmptySet("f", setOf("ff", "eff")).hashCode() 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/set/assertSetOperationEquals.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.set 2 | 3 | import com.quickbirdstudios.nonEmptyCollection.assertOperationEquals 4 | 5 | fun assertSetOperationEquals( 6 | expected: Set.() -> R, 7 | actual: NonEmptySet.() -> R, 8 | element: T, 9 | vararg elements: T 10 | ) = assertOperationEquals( 11 | expected = { toSet().expected() }, 12 | actual = { toNonEmptySet().actual() }, 13 | element = element, 14 | elements = elements 15 | ) 16 | 17 | fun assertSetOperationEquals( 18 | expected: Set.(P) -> R, 19 | actual: NonEmptySet.(P) -> R, 20 | parameter: P, 21 | element: T, 22 | vararg elements: T 23 | ) = assertOperationEquals( 24 | expected = { p -> toSet().expected(p) }, 25 | actual = { p -> toNonEmptySet().actual(p) }, 26 | parameter = parameter, 27 | element = element, 28 | elements = elements 29 | ) 30 | 31 | fun assertSetOperationEquals( 32 | expected: Set.(P1, P2) -> R, 33 | actual: NonEmptySet.(P1, P2) -> R, 34 | parameter1: P1, 35 | parameter2: P2, 36 | element: T, 37 | vararg elements: T 38 | ) = assertOperationEquals( 39 | expected = { p1, p2 -> toSet().expected(p1, p2) }, 40 | actual = { p1, p2 -> toNonEmptySet().actual(p1, p2) }, 41 | parameter1 = parameter1, 42 | parameter2 = parameter2, 43 | element = element, 44 | elements = elements 45 | ) 46 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/unsafe/AddUnitParameterTest.kt: -------------------------------------------------------------------------------- 1 | package com.quickbirdstudios.nonEmptyCollection.unsafe 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class AddUnitParameterTest { 7 | @Test 8 | fun zeroParameters() { 9 | val function = fun() = 69 10 | 11 | assertEquals(function(), function.addUnitParameter().invoke(Unit)) 12 | } 13 | 14 | @Test 15 | fun oneParameter() { 16 | val function = fun(x: Int) = 69 * x 17 | 18 | assertEquals(function(42), function.addUnitParameter().invoke(42, Unit)) 19 | } 20 | 21 | @Test 22 | fun twoParameters() { 23 | val function = fun(x: Int, y: Float) = 69 * x / y 24 | 25 | assertEquals(function(42, 420f), function.addUnitParameter().invoke(42, 420f, Unit)) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/quickbirdstudios/nonEmptyCollection/unsafe/ToNonEmptyCollectionTest.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(UnsafeNonEmptyCollectionApi::class) 2 | 3 | package com.quickbirdstudios.nonEmptyCollection.unsafe 4 | 5 | import com.quickbirdstudios.nonEmptyCollection.assertThrows 6 | import com.quickbirdstudios.nonEmptyCollection.list.nonEmptyListOf 7 | import com.quickbirdstudios.nonEmptyCollection.map.NonEmptyMap 8 | import com.quickbirdstudios.nonEmptyCollection.map.nonEmptyMapOf 9 | import com.quickbirdstudios.nonEmptyCollection.set.nonEmptySetOf 10 | import kotlin.test.Test 11 | import kotlin.test.assertEquals 12 | 13 | class ToNonEmptyCollectionTest { 14 | 15 | @Test 16 | fun toNonEmptyList() { 17 | assertEquals(nonEmptyListOf(15, 2), listOf(15, 2).toNonEmptyList()) 18 | assertThrows { 19 | emptyList().toNonEmptyList() 20 | } 21 | } 22 | 23 | @Test 24 | fun toNonEmptySet() { 25 | assertEquals(nonEmptySetOf(15, 2), listOf(15, 2).toNonEmptySet()) 26 | assertEquals(nonEmptySetOf(15, 2), setOf(15, 2).toNonEmptySet()) 27 | 28 | assertThrows { 29 | emptyList().toNonEmptySet() 30 | } 31 | assertThrows { 32 | emptySet().toNonEmptySet() 33 | } 34 | } 35 | 36 | @Test 37 | fun toNonEmptyMap() { 38 | assertEquals>( 39 | nonEmptyMapOf(15 to 't', 2 to 'P'), 40 | listOf(15 to 't', 2 to 'P').toNonEmptyMap() 41 | ) 42 | assertEquals>( 43 | nonEmptyMapOf(15 to 't', 2 to 'P'), 44 | mapOf(15 to 't', 2 to 'P').toNonEmptyMap() 45 | ) 46 | 47 | assertThrows { 48 | emptyList>().toNonEmptyMap() 49 | } 50 | assertThrows { 51 | emptyMap().toNonEmptyMap() 52 | } 53 | } 54 | 55 | } 56 | --------------------------------------------------------------------------------