mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 06:00:22 +00:00 
			
		
		
		
	Compare commits
	
		
			142 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1d8330015d | |||
| e5017b0258 | |||
| cd412ca31b | |||
| d2b6473095 | |||
| ab42507275 | |||
| dcef844e20 | |||
| 3244708c1b | |||
| 73ac1f1741 | |||
| f104e9f352 | |||
| 393c9a7d06 | |||
| ea497ea488 | |||
| 
						 | 
					5add89cad0 | ||
| 2db447d2ef | |||
| 31c83813e6 | |||
| 27483a282d | |||
| 48b816aa22 | |||
| 0065f94f52 | |||
| ccc0002eb2 | |||
| 15a2eee141 | |||
| b9faac71e5 | |||
| 0a4465de33 | |||
| f9dfd09628 | |||
| 8638d7afce | |||
| 8311793a43 | |||
| 0d552cfcd2 | |||
| 4b0f20dbd1 | |||
| cf531c949d | |||
| ba5c5f17d5 | |||
| 35825ad9b7 | |||
| b1eb26a89e | |||
| c9d04b6698 | |||
| 496133e014 | |||
| f2857ee2be | |||
| 22541f2d5e | |||
| e235c52b6c | |||
| e89b8c72dd | |||
| a374e53a3a | |||
| afb066c4ee | |||
| f05761d4a5 | |||
| 76adc9ea33 | |||
| 99dd291413 | |||
| f904eb27e1 | |||
| eeb8214812 | |||
| f7215b039e | |||
| c07fe5a0f9 | |||
| 0d28cb6e20 | |||
| a1a17bfd1f | |||
| f386f09592 | |||
| a47e17fe6e | |||
| 01dc3b63ff | |||
| 2d97e0699e | |||
| 75f514d99b | |||
| 9a687cfc1c | |||
| 14edf8b6b7 | |||
| 23aa2d8917 | |||
| 7651388b5c | |||
| 805ab32b24 | |||
| cc623b1097 | |||
| 1420416b3e | |||
| 9a0b67f938 | |||
| 303e1e6281 | |||
| ff59b0cc9c | |||
| be5d2ee715 | |||
| 8dd2e3f6f9 | |||
| 2eedd196d2 | |||
| 759a3f2784 | |||
| 386fa830c3 | |||
| c382423d77 | |||
| bb466ce66c | |||
| 72cd3dd8a1 | |||
| 
						 | 
					595cedaaf1 | ||
| eeaceb6cf5 | |||
| 1bd671685b | |||
| 48d3fe41f2 | |||
| 7ab21871cd | |||
| 65d01b1fb3 | |||
| 6230accb68 | |||
| c6ed821934 | |||
| 10e03bb951 | |||
| aa4f392948 | |||
| f51b59ec02 | |||
| 8c76834ae4 | |||
| 4a454f3d67 | |||
| 151aa1863d | |||
| 3bf6896296 | |||
| 0d01561476 | |||
| f6ded92251 | |||
| d01b735cc6 | |||
| 6c12001080 | |||
| 1afbf03606 | |||
| f6ef5c61c5 | |||
| c18fee8107 | |||
| d9df7a4384 | |||
| 87c2230e8e | |||
| da7eb6de0a | |||
| ed3815118f | |||
| be726f42bd | |||
| a91006132f | |||
| 9a9f741a0b | |||
| 5028f130e9 | |||
| 77fa019651 | |||
| 9715da9384 | |||
| f6d5035c1a | |||
| 43e782ab6f | |||
| f3f9920bfb | |||
| 2bfd615812 | |||
| ebfacb3659 | |||
| c71d557eec | |||
| e0398cef21 | |||
| f91599e9c6 | |||
| f8f9f93c97 | |||
| a8a5340d8b | |||
| 871b27f37d | |||
| 6f174cae1d | |||
| 22d7ac3e22 | |||
| 9b30c3a155 | |||
| 915bac64b1 | |||
| 9d2b50e55d | |||
| bde100f63d | |||
| 05b035a13d | |||
| eefb56bed7 | |||
| fcc0dc4189 | |||
| 47ff20317f | |||
| 1558b9103d | |||
| 7a78742162 | |||
| c01e240f66 | |||
| fef4fcbac6 | |||
| 5ab18bce4b | |||
| 24aec7271a | |||
| 9b19a2cb95 | |||
| efdd7b8a57 | |||
| 6df4cc9c3b | |||
| b9d93db0f5 | |||
| d7ee45ca64 | |||
| d7c31b1b22 | |||
| 7d6794a358 | |||
| 473eb87346 | |||
| 8b18b07790 | |||
| ab3c80a5ec | |||
| 075b93ecd6 | |||
| f6d0f72e49 | |||
| fcda3af862 | 
							
								
								
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							@@ -8,7 +8,7 @@ jobs:
 | 
				
			|||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
      - uses: actions/setup-java@v1
 | 
					      - uses: actions/setup-java@v1
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          java-version: 11
 | 
					          java-version: 17
 | 
				
			||||||
      - name: Rewrite version
 | 
					      - name: Rewrite version
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
 | 
					          branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/dokka_push.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/dokka_push.yml
									
									
									
									
										vendored
									
									
								
							@@ -10,7 +10,7 @@ jobs:
 | 
				
			|||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
      - uses: actions/setup-java@v1
 | 
					      - uses: actions/setup-java@v1
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          java-version: 11
 | 
					          java-version: 17
 | 
				
			||||||
      - name: Build
 | 
					      - name: Build
 | 
				
			||||||
        run: ./gradlew build && ./gradlew dokkaHtml
 | 
					        run: ./gradlew build && ./gradlew dokkaHtml
 | 
				
			||||||
      - name: Publish KDocs
 | 
					      - name: Publish KDocs
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										205
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										205
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,5 +1,210 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `KSLog`: `1.3.2` -> `1.3.3`
 | 
				
			||||||
 | 
					    * `Exposed`: `0.48.0` -> `0.49.0`
 | 
				
			||||||
 | 
					    * `UUID`: `0.8.2` -> `0.8.4`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.39
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin`: `1.9.22` -> `1.9.23`
 | 
				
			||||||
 | 
					    * `Korlibs`: `5.3.2` -> `5.4.0`
 | 
				
			||||||
 | 
					    * `Okio`: `3.8.0` -> `3.9.0`
 | 
				
			||||||
 | 
					    * `Compose`: `1.6.0` -> `1.6.1`
 | 
				
			||||||
 | 
					    * `ComposeMaterial3`: `1.2.0` -> `1.2.1`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.38
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Ktor`: `2.3.8` -> `2.3.9`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.37
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Compose`: `1.5.12` -> `1.6.0`
 | 
				
			||||||
 | 
					    * `Exposed`: `0.47.0` -> `0.48.0`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.36
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Serialization`: `1.6.2` -> `1.6.3`
 | 
				
			||||||
 | 
					    * `Korlibs`: `5.3.1` -> `5.3.2`
 | 
				
			||||||
 | 
					* `Repos`:
 | 
				
			||||||
 | 
					    * `Cache`:
 | 
				
			||||||
 | 
					        * Improve work and functionality of `actualizeAll` and subsequent functions
 | 
				
			||||||
 | 
					        * All internal repos `invalidate`/`actualizeAll` now use common `actualizeAll` functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.35
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Coroutines`: `1.7.3` -> `1.8.0`
 | 
				
			||||||
 | 
					    * `Material3`: `1.1.2` -> `1.2.0`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.34
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Repos`:
 | 
				
			||||||
 | 
					    * `Common`:
 | 
				
			||||||
 | 
					        * Improve default `set` realization of `KeyValuesRepo`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Colors`
 | 
				
			||||||
 | 
					    * `Common`:
 | 
				
			||||||
 | 
					        * Add opportunity to use `HEXAColor` with `ahex` colors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Okio`: `3.7.0` -> `3.8.0`
 | 
				
			||||||
 | 
					* `Resources`:
 | 
				
			||||||
 | 
					    * Make `StringResource` serializable
 | 
				
			||||||
 | 
					    * Add several variants of builder usages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Ktor`: `2.3.7` -> `2.3.8`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Exposed`: `0.46.0` -> `0.47.0`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.29
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin`: `1.9.21` -> `1.9.22`
 | 
				
			||||||
 | 
					    * `Compose`: `1.5.11` -> `1.5.12`
 | 
				
			||||||
 | 
					    * `Korlibs`: `5.3.0` -> `5.3.1`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.28
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin`: `1.9.22` -> `1.9.21` (downgrade)
 | 
				
			||||||
 | 
					    * `Compose`: `1.6.0-dev13691` -> `1.5.11` (downgrade)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.27
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin`: `1.9.21` -> `1.9.22`
 | 
				
			||||||
 | 
					    * `Compose`: `1.5.11` -> `1.6.0-dev13691`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.26
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Exposed`: `0.45.0` -> `0.46.0`. **This update brinds new api deprecations in exposed**
 | 
				
			||||||
 | 
					* `Resources`:
 | 
				
			||||||
 | 
					    * Add opportunity to get default translation by passing `null` as `IetfLang` argument
 | 
				
			||||||
 | 
					    * Add several useful extensions to get translations in `JS` target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.25
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Colors`:
 | 
				
			||||||
 | 
					    * `Common`:
 | 
				
			||||||
 | 
					        * Module inited
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Since this version depdendencies of klock and krypto replaced with `com.soywiz.korge:korlibs-time` and `com.soywiz.korge:korlibs-crypto`**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Klock` (since now `KorlibsTime`): `4.0.10` -> `5.3.0`
 | 
				
			||||||
 | 
					    * `Krypto` (since now `KorlibsCrypto`): `4.0.10` -> `5.3.0`
 | 
				
			||||||
 | 
					* `Serialization`:
 | 
				
			||||||
 | 
					    * `Mapper`:
 | 
				
			||||||
 | 
					        * `Mapper` pass decoder into callback of deserialization strategy
 | 
				
			||||||
 | 
					        * `Mapper` pass encoder into callback of serialization strategy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Koin`: `3.5.0` -> `3.5.3`
 | 
				
			||||||
 | 
					    * `Okio`: `3.6.0` -> `3.7.0`
 | 
				
			||||||
 | 
					* `LanguageCodes`:
 | 
				
			||||||
 | 
					    * Fixes in intermediate language codes (like `Chinese.Hans`)
 | 
				
			||||||
 | 
					    * Rename `IetfLanguageCode` to `IetfLang`
 | 
				
			||||||
 | 
					        * Rename all subsequent functions (including serializer)
 | 
				
			||||||
 | 
					    * New lazy properties `knownLanguageCodesMap`, `knownLanguageCodesMapByLowerCasedKeys` and several others
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Common`:
 | 
				
			||||||
 | 
					    * Add opportunity to create own `Diff` with base constructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.21
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Resources`:
 | 
				
			||||||
 | 
					    * Inited
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Repos`:
 | 
				
			||||||
 | 
					    * `Exposed`:
 | 
				
			||||||
 | 
					        * Add opportunity for setup flows in `AbstractExposedCRUDRepo`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Ktor`: `2.3.6` -> `2.3.7`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					    * `SpecialMutableStateFlow` now extends `MutableStateFlow`
 | 
				
			||||||
 | 
					    * `Compose`:
 | 
				
			||||||
 | 
					        * Deprecate `FlowState` due to its complexity in fixes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Serialization`: `1.6.1` -> `1.6.2`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Exposed`: `0.44.1` -> `0.45.0`
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					    * Add `SpecialMutableStateFlow`
 | 
				
			||||||
 | 
					    * `Compose`:
 | 
				
			||||||
 | 
					        * Add `FlowState`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin`: `1.9.20` -> `1.9.21`
 | 
				
			||||||
 | 
					    * `KSLog`: `1.3.0` -> `1.3.1`
 | 
				
			||||||
 | 
					    * `Compose`: `1.5.10` -> `1.5.11`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Serialization`: `1.6.0` -> `1.6.1`
 | 
				
			||||||
 | 
					    * `KSLog`: `1.2.4` -> `1.3.0`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Ktor`: `2.3.5` -> `2.3.6`
 | 
				
			||||||
 | 
					    * `UUID`: `0.8.1` -> `0.8.2`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**It is experimental migration onto new gradle version. Be careful in use of this version**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**This update have JDK 17 in `compatibility` and `target` versions**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Kotlin`: `1.9.20-RC2` -> `1.9.20`
 | 
				
			||||||
 | 
					    * `Exposed`: `0.44.0` -> `0.44.1`
 | 
				
			||||||
 | 
					    * `Compose`: `1.5.10-rc02` -> `1.5.10`
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					    * `SmartRWLocker` now will wait first unlock of write mutex for acquiring read
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.20.10
 | 
					## 0.20.10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `Versions`:
 | 
					* `Versions`:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,7 @@ allprojects {
 | 
				
			|||||||
        mavenCentral()
 | 
					        mavenCentral()
 | 
				
			||||||
        google()
 | 
					        google()
 | 
				
			||||||
        maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" }
 | 
					        maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" }
 | 
				
			||||||
        maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
 | 
					        maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // temporal crutch until legacy tests will be stabled or legacy target will be removed
 | 
					    // temporal crutch until legacy tests will be stabled or legacy target will be removed
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								colors/common/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								colors/common/build.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.multiplatform"
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.plugin.serialization"
 | 
				
			||||||
 | 
					    id "com.android.library"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64ProjectPresetPath"
 | 
				
			||||||
							
								
								
									
										174
									
								
								colors/common/src/commonMain/kotlin/HEXAColor.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								colors/common/src/commonMain/kotlin/HEXAColor.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.colors.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					import kotlin.jvm.JvmInline
 | 
				
			||||||
 | 
					import kotlin.math.floor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Wrapper for RGBA colors. Receiving [UInt] in main constructor. Each part in main constructor
 | 
				
			||||||
 | 
					 * configured with `0x00 - 0xff` range. Examples:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * * Red: `0xff0000ffu`
 | 
				
			||||||
 | 
					 * * Red (0.5 capacity): `0xff000088u`
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Anyway it is recommended to use
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param hexaUInt rgba [UInt] in format `0xFFEEBBAA` where FF - red, EE - green, BB - blue` and AA - alpha
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					@JvmInline
 | 
				
			||||||
 | 
					value class HEXAColor (
 | 
				
			||||||
 | 
					    val hexaUInt: UInt
 | 
				
			||||||
 | 
					) : Comparable<HEXAColor> {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @returns [hexaUInt] as a string with format `#FFEEBBAA` where FF - red, EE - green, BB - blue and AA - alpha
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    val hexa: String
 | 
				
			||||||
 | 
					        get() = "#${hexaUInt.toString(16).padStart(8, '0')}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @returns [hexaUInt] as a string with format `#FFEEBB` where FF - red, EE - green and BB - blue
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    val hex: String
 | 
				
			||||||
 | 
					        get() = hexa.take(7)
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @returns [hexaUInt] as a string with format `#AAFFEEBB` where AA - alpha, FF - red, EE - green and BB - blue
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    val ahex: String
 | 
				
			||||||
 | 
					        get() = "#${a.toString(16).padStart(2, '2')}${hex.drop(1)}"
 | 
				
			||||||
 | 
					    val rgba: String
 | 
				
			||||||
 | 
					        get() = "rgba($r,$g,$b,${aOfOne.toString().take(5)})"
 | 
				
			||||||
 | 
					    val rgb: String
 | 
				
			||||||
 | 
					        get() = "rgb($r,$g,$b)"
 | 
				
			||||||
 | 
					    val shortHex: String
 | 
				
			||||||
 | 
					        get() = "#${r.shortPart()}${g.shortPart()}${b.shortPart()}"
 | 
				
			||||||
 | 
					    val shortHexa: String
 | 
				
			||||||
 | 
					        get() = "$shortHex${a.shortPart()}"
 | 
				
			||||||
 | 
					    val rgbUInt: UInt
 | 
				
			||||||
 | 
					        get() = (hexaUInt / 256u)
 | 
				
			||||||
 | 
					    val rgbInt: Int
 | 
				
			||||||
 | 
					        get() = rgbUInt.toInt()
 | 
				
			||||||
 | 
					    val ahexUInt
 | 
				
			||||||
 | 
					        get() = (a * 0x1000000).toUInt() + rgbUInt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val r: Int
 | 
				
			||||||
 | 
					        get() = ((hexaUInt and 0xff000000u) / 0x1000000u).toInt()
 | 
				
			||||||
 | 
					    val g: Int
 | 
				
			||||||
 | 
					        get() = ((hexaUInt and 0x00ff0000u) / 0x10000u).toInt()
 | 
				
			||||||
 | 
					    val b: Int
 | 
				
			||||||
 | 
					        get() = ((hexaUInt and 0x0000ff00u) / 0x100u).toInt()
 | 
				
			||||||
 | 
					    val a: Int
 | 
				
			||||||
 | 
					        get() = ((hexaUInt and 0x000000ffu)).toInt()
 | 
				
			||||||
 | 
					    val aOfOne: Float
 | 
				
			||||||
 | 
					        get() = a.toFloat() / (0xff)
 | 
				
			||||||
 | 
					    init {
 | 
				
			||||||
 | 
					        require(hexaUInt in 0u ..0xffffffffu)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(r: Int, g: Int, b: Int, a: Int) : this(
 | 
				
			||||||
 | 
					        ((r * 0x1000000).toLong() + g * 0x10000 + b * 0x100 + a).toUInt()
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        require(r in 0 ..0xff)
 | 
				
			||||||
 | 
					        require(g in 0 ..0xff)
 | 
				
			||||||
 | 
					        require(b in 0 ..0xff)
 | 
				
			||||||
 | 
					        require(a in 0 ..0xff)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(r: Int, g: Int, b: Int, aOfOne: Float = 1f) : this(
 | 
				
			||||||
 | 
					        r = r, g = g, b = b, a = (aOfOne * 0xff).toInt()
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun toString(): String {
 | 
				
			||||||
 | 
					        return hexa
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun compareTo(other: HEXAColor): Int = (hexaUInt - other.hexaUInt).coerceIn(Int.MIN_VALUE.toUInt(), Int.MAX_VALUE.toLong().toUInt()).toInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun copy(
 | 
				
			||||||
 | 
					        r: Int = this.r,
 | 
				
			||||||
 | 
					        g: Int = this.g,
 | 
				
			||||||
 | 
					        b: Int = this.b,
 | 
				
			||||||
 | 
					        aOfOne: Float = this.aOfOne
 | 
				
			||||||
 | 
					    ) = HEXAColor(r = r, g = g, b = b, aOfOne = aOfOne)
 | 
				
			||||||
 | 
					    fun copy(
 | 
				
			||||||
 | 
					        r: Int = this.r,
 | 
				
			||||||
 | 
					        g: Int = this.g,
 | 
				
			||||||
 | 
					        b: Int = this.b,
 | 
				
			||||||
 | 
					        a: Int
 | 
				
			||||||
 | 
					    ) = HEXAColor(r = r, g = g, b = b, a = a)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Parsing color from [color]
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * Supported formats samples (on Red color based):
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * * `#f00`
 | 
				
			||||||
 | 
					         * * `#f00f`
 | 
				
			||||||
 | 
					         * * `#ff0000`
 | 
				
			||||||
 | 
					         * * `#ff0000ff`
 | 
				
			||||||
 | 
					         * * `rgb(255, 0, 0)`
 | 
				
			||||||
 | 
					         * * `rgba(255, 0, 0, 1)`
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        fun parseStringColor(color: String): HEXAColor = when {
 | 
				
			||||||
 | 
					            color.startsWith("#") -> color.removePrefix("#").let { color ->
 | 
				
			||||||
 | 
					                when (color.length) {
 | 
				
			||||||
 | 
					                    3 -> color.map { "$it$it" }.joinToString(separator = "", postfix = "ff")
 | 
				
			||||||
 | 
					                    4 -> color.take(3).map { "$it$it" }.joinToString(separator = "", postfix = color.takeLast(1).let { "${it}0" })
 | 
				
			||||||
 | 
					                    6 -> "${color}ff"
 | 
				
			||||||
 | 
					                    8 -> color
 | 
				
			||||||
 | 
					                    else -> error("Malfurmed color string: $color. It is expected that color started with # will contains 3, 6 or 8 valuable parts")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            color.startsWith("rgb(") -> color
 | 
				
			||||||
 | 
					                .removePrefix("rgb(")
 | 
				
			||||||
 | 
					                .removeSuffix(")")
 | 
				
			||||||
 | 
					                .replace(Regex("\\s"), "")
 | 
				
			||||||
 | 
					                .split(",")
 | 
				
			||||||
 | 
					                .joinToString("", postfix = "ff") {
 | 
				
			||||||
 | 
					                    it.toInt().toString(16).padStart(2, '0')
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            color.startsWith("rgba(") -> color
 | 
				
			||||||
 | 
					                .removePrefix("rgba(")
 | 
				
			||||||
 | 
					                .removeSuffix(")")
 | 
				
			||||||
 | 
					                .replace(Regex("\\s"), "")
 | 
				
			||||||
 | 
					                .split(",").let {
 | 
				
			||||||
 | 
					                    it.take(3).map { it.toInt().toString(16).padStart(2, '0') } + (it.last().toFloat() * 0xff).toInt().toString(16).padStart(2, '0')
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                .joinToString("")
 | 
				
			||||||
 | 
					            else -> color
 | 
				
			||||||
 | 
					        }.lowercase().toUInt(16).let(::HEXAColor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Creates [HEXAColor] from [uint] presume it is in format `0xFFEEBBAA` where FF - red, EE - green, BB - blue` and AA - alpha
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        fun fromHexa(uint: UInt) = HEXAColor(uint)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Creates [HEXAColor] from [uint] presume it is in format `0xAAFFEEBB` where AA - alpha, FF - red, EE - green and BB - blue`
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        fun fromAhex(uint: UInt) = HEXAColor(
 | 
				
			||||||
 | 
					            a = ((uint and 0xff000000u) / 0x1000000u).toInt(),
 | 
				
			||||||
 | 
					            r = ((uint and 0x00ff0000u) / 0x10000u).toInt(),
 | 
				
			||||||
 | 
					            g = ((uint and 0x0000ff00u) / 0x100u).toInt(),
 | 
				
			||||||
 | 
					            b = ((uint and 0x000000ffu)).toInt()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Parsing color from [color]
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * Supported formats samples (on Red color based):
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * * `#f00`
 | 
				
			||||||
 | 
					         * * `#ff0000`
 | 
				
			||||||
 | 
					         * * `#ff0000ff`
 | 
				
			||||||
 | 
					         * * `rgb(255, 0, 0)`
 | 
				
			||||||
 | 
					         * * `rgba(255, 0, 0, 1)`
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        operator fun invoke(color: String) = parseStringColor(color)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private fun Int.shortPart(): String {
 | 
				
			||||||
 | 
					            return (floor(toFloat() / 16)).toInt().toString(16)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										209
									
								
								colors/common/src/commonTest/kotlin/HexColorTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								colors/common/src/commonTest/kotlin/HexColorTests.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,209 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.colors.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlin.math.floor
 | 
				
			||||||
 | 
					import kotlin.test.Test
 | 
				
			||||||
 | 
					import kotlin.test.assertEquals
 | 
				
			||||||
 | 
					import kotlin.test.assertTrue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HexColorTests {
 | 
				
			||||||
 | 
					    val alphaRgbaPrecision = 5
 | 
				
			||||||
 | 
					    class TestColor(
 | 
				
			||||||
 | 
					        val color: HEXAColor,
 | 
				
			||||||
 | 
					        val shortHex: String,
 | 
				
			||||||
 | 
					        val shortHexa: String,
 | 
				
			||||||
 | 
					        val hex: String,
 | 
				
			||||||
 | 
					        val hexa: String,
 | 
				
			||||||
 | 
					        val ahex: String,
 | 
				
			||||||
 | 
					        val ahexUInt: UInt,
 | 
				
			||||||
 | 
					        val rgbUInt: UInt,
 | 
				
			||||||
 | 
					        val rgb: String,
 | 
				
			||||||
 | 
					        val rgba: String,
 | 
				
			||||||
 | 
					        val r: Int,
 | 
				
			||||||
 | 
					        val g: Int,
 | 
				
			||||||
 | 
					        val b: Int,
 | 
				
			||||||
 | 
					        val a: Int,
 | 
				
			||||||
 | 
					        vararg val additionalRGBAVariants: String
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    val testColors: List<TestColor>
 | 
				
			||||||
 | 
					        get() = listOf(
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(hexaUInt = 0xff0000ffu),
 | 
				
			||||||
 | 
					                shortHex = "#f00",
 | 
				
			||||||
 | 
					                shortHexa = "#f00f",
 | 
				
			||||||
 | 
					                hex = "#ff0000",
 | 
				
			||||||
 | 
					                hexa = "#ff0000ff",
 | 
				
			||||||
 | 
					                ahex = "#ffff0000",
 | 
				
			||||||
 | 
					                ahexUInt = 0xffff0000u,
 | 
				
			||||||
 | 
					                rgbUInt = 0xff0000u,
 | 
				
			||||||
 | 
					                rgb = "rgb(255,0,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(255,0,0,1.0)",
 | 
				
			||||||
 | 
					                r = 0xff,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0xff,
 | 
				
			||||||
 | 
					                "rgba(255,0,0,1)",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(hexaUInt = 0x00ff00ffu),
 | 
				
			||||||
 | 
					                shortHex = "#0f0",
 | 
				
			||||||
 | 
					                shortHexa = "#0f0f",
 | 
				
			||||||
 | 
					                hex = "#00ff00",
 | 
				
			||||||
 | 
					                hexa = "#00ff00ff",
 | 
				
			||||||
 | 
					                ahex = "#ff00ff00",
 | 
				
			||||||
 | 
					                ahexUInt = 0xff00ff00u,
 | 
				
			||||||
 | 
					                rgbUInt = 0x00ff00u,
 | 
				
			||||||
 | 
					                rgb = "rgb(0,255,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,255,0,1.0)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0xff,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0xff,
 | 
				
			||||||
 | 
					                "rgba(0,255,0,1)"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x0000ffffu),
 | 
				
			||||||
 | 
					                shortHex = "#00f",
 | 
				
			||||||
 | 
					                shortHexa = "#00ff",
 | 
				
			||||||
 | 
					                hex = "#0000ff",
 | 
				
			||||||
 | 
					                hexa = "#0000ffff",
 | 
				
			||||||
 | 
					                ahex = "#ff0000ff",
 | 
				
			||||||
 | 
					                ahexUInt = 0xff0000ffu,
 | 
				
			||||||
 | 
					                rgbUInt = 0x0000ffu,
 | 
				
			||||||
 | 
					                rgb = "rgb(0,0,255)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,0,255,1.0)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0xff,
 | 
				
			||||||
 | 
					                a = 0xff,
 | 
				
			||||||
 | 
					                "rgba(0,0,255,1)"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0xff000088u),
 | 
				
			||||||
 | 
					                shortHex = "#f00",
 | 
				
			||||||
 | 
					                shortHexa = "#f008",
 | 
				
			||||||
 | 
					                hex = "#ff0000",
 | 
				
			||||||
 | 
					                hexa = "#ff000088",
 | 
				
			||||||
 | 
					                ahex = "#88ff0000",
 | 
				
			||||||
 | 
					                ahexUInt = 0x88ff0000u,
 | 
				
			||||||
 | 
					                rgbUInt = 0xff0000u,
 | 
				
			||||||
 | 
					                rgb = "rgb(255,0,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(255,0,0,0.533)",
 | 
				
			||||||
 | 
					                r = 0xff,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0x88,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x00ff0088u),
 | 
				
			||||||
 | 
					                shortHex = "#0f0",
 | 
				
			||||||
 | 
					                shortHexa = "#0f08",
 | 
				
			||||||
 | 
					                hex = "#00ff00",
 | 
				
			||||||
 | 
					                hexa = "#00ff0088",
 | 
				
			||||||
 | 
					                ahex = "#8800ff00",
 | 
				
			||||||
 | 
					                ahexUInt = 0x8800ff00u,
 | 
				
			||||||
 | 
					                rgbUInt = 0x00ff00u,
 | 
				
			||||||
 | 
					                rgb = "rgb(0,255,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,255,0,0.533)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0xff,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0x88,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x0000ff88u),
 | 
				
			||||||
 | 
					                shortHex = "#00f",
 | 
				
			||||||
 | 
					                shortHexa = "#00f8",
 | 
				
			||||||
 | 
					                hex = "#0000ff",
 | 
				
			||||||
 | 
					                hexa = "#0000ff88",
 | 
				
			||||||
 | 
					                ahex = "#880000ff",
 | 
				
			||||||
 | 
					                ahexUInt = 0x880000ffu,
 | 
				
			||||||
 | 
					                rgbUInt = 0x0000ffu,
 | 
				
			||||||
 | 
					                rgb = "rgb(0,0,255)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,0,255,0.533)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0xff,
 | 
				
			||||||
 | 
					                a = 0x88,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0xff000022u),
 | 
				
			||||||
 | 
					                shortHex = "#f00",
 | 
				
			||||||
 | 
					                shortHexa = "#f002",
 | 
				
			||||||
 | 
					                hex = "#ff0000",
 | 
				
			||||||
 | 
					                hexa = "#ff000022",
 | 
				
			||||||
 | 
					                ahex = "#22ff0000",
 | 
				
			||||||
 | 
					                ahexUInt = 0x22ff0000u,
 | 
				
			||||||
 | 
					                rgbUInt = 0xff0000u,
 | 
				
			||||||
 | 
					                rgb = "rgb(255,0,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(255,0,0,0.133)",
 | 
				
			||||||
 | 
					                r = 0xff,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0x22,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x00ff0022u),
 | 
				
			||||||
 | 
					                shortHex = "#0f0",
 | 
				
			||||||
 | 
					                shortHexa = "#0f02",
 | 
				
			||||||
 | 
					                hex = "#00ff00",
 | 
				
			||||||
 | 
					                hexa = "#00ff0022",
 | 
				
			||||||
 | 
					                ahex = "#2200ff00",
 | 
				
			||||||
 | 
					                ahexUInt = 0x2200ff00u,
 | 
				
			||||||
 | 
					                rgbUInt = 0x00ff00u,
 | 
				
			||||||
 | 
					                rgb = "rgb(0,255,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,255,0,0.133)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0xff,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0x22,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x0000ff22u),
 | 
				
			||||||
 | 
					                shortHex = "#00f",
 | 
				
			||||||
 | 
					                shortHexa = "#00f2",
 | 
				
			||||||
 | 
					                hex = "#0000ff",
 | 
				
			||||||
 | 
					                hexa = "#0000ff22",
 | 
				
			||||||
 | 
					                ahex = "#220000ff",
 | 
				
			||||||
 | 
					                ahexUInt = 0x220000ffu,
 | 
				
			||||||
 | 
					                rgbUInt = 0x0000ffu,
 | 
				
			||||||
 | 
					                rgb = "rgb(0,0,255)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,0,255,0.133)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0xff,
 | 
				
			||||||
 | 
					                a = 0x22,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun baseTest() {
 | 
				
			||||||
 | 
					        testColors.forEach {
 | 
				
			||||||
 | 
					            assertEquals(it.hex, it.color.hex)
 | 
				
			||||||
 | 
					            assertEquals(it.hexa, it.color.hexa)
 | 
				
			||||||
 | 
					            assertEquals(it.ahex, it.color.ahex)
 | 
				
			||||||
 | 
					            assertEquals(it.rgbUInt, it.color.rgbUInt)
 | 
				
			||||||
 | 
					            assertEquals(it.ahexUInt, it.color.ahexUInt)
 | 
				
			||||||
 | 
					            assertEquals(it.shortHex, it.color.shortHex)
 | 
				
			||||||
 | 
					            assertEquals(it.shortHexa, it.color.shortHexa)
 | 
				
			||||||
 | 
					            assertEquals(it.rgb, it.color.rgb)
 | 
				
			||||||
 | 
					            assertTrue(it.rgba == it.color.rgba || it.color.rgba in it.additionalRGBAVariants)
 | 
				
			||||||
 | 
					            assertEquals(it.r, it.color.r)
 | 
				
			||||||
 | 
					            assertEquals(it.g, it.color.g)
 | 
				
			||||||
 | 
					            assertEquals(it.b, it.color.b)
 | 
				
			||||||
 | 
					            assertEquals(it.a, it.color.a)
 | 
				
			||||||
 | 
					            assertEquals(it.color, HEXAColor.fromAhex(it.ahexUInt))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun testHexParseColor() {
 | 
				
			||||||
 | 
					        testColors.forEach {
 | 
				
			||||||
 | 
					            assertEquals(it.color.copy(aOfOne = 1f), HEXAColor.parseStringColor(it.hex))
 | 
				
			||||||
 | 
					            assertEquals(it.color, HEXAColor.parseStringColor(it.hexa))
 | 
				
			||||||
 | 
					            assertEquals(it.color.copy(aOfOne = 1f), HEXAColor.parseStringColor(it.rgb))
 | 
				
			||||||
 | 
					            assertTrue(it.color.hexaUInt.toInt() - HEXAColor.parseStringColor(it.rgba).hexaUInt.toInt() in -0x1 .. 0x1, )
 | 
				
			||||||
 | 
					            assertEquals(it.color.copy(aOfOne = 1f), HEXAColor.parseStringColor(it.shortHex))
 | 
				
			||||||
 | 
					            assertEquals(it.color.copy(a = floor(it.color.a.toFloat() / 16).toInt() * 0x10), HEXAColor.parseStringColor(it.shortHexa))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -27,7 +27,7 @@ private inline fun <T> getObject(
 | 
				
			|||||||
 * @see calculateDiff
 | 
					 * @see calculateDiff
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
data class Diff<T> internal constructor(
 | 
					data class Diff<T> @Warning(warning) constructor(
 | 
				
			||||||
    val removed: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>,
 | 
					    val removed: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>,
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Old-New values pairs
 | 
					     * Old-New values pairs
 | 
				
			||||||
@@ -36,6 +36,10 @@ data class Diff<T> internal constructor(
 | 
				
			|||||||
    val added: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>
 | 
					    val added: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    fun isEmpty(): Boolean = removed.isEmpty() && replaced.isEmpty() && added.isEmpty()
 | 
					    fun isEmpty(): Boolean = removed.isEmpty() && replaced.isEmpty() && added.isEmpty()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        private const val warning = "This feature can be changed without any warranties. Use with caution and only in case you know what you are doing"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <T> emptyDiff(): Diff<T> = Diff(emptyList(), emptyList(), emptyList())
 | 
					fun <T> emptyDiff(): Diff<T> = Diff(emptyList(), emptyList(), emptyList())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines.compose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.compose.runtime.MutableState
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This type works like [MutableState], [kotlinx.coroutines.flow.StateFlow] and [kotlinx.coroutines.flow.MutableSharedFlow].
 | 
				
			||||||
 | 
					 * Based on [SpecialMutableStateFlow]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Deprecated("Will be removed soon")
 | 
				
			||||||
 | 
					class FlowState<T>(
 | 
				
			||||||
 | 
					    initial: T,
 | 
				
			||||||
 | 
					    internalScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
				
			||||||
 | 
					) : MutableState<T>,
 | 
				
			||||||
 | 
					    SpecialMutableStateFlow<T>(initial, internalScope) {
 | 
				
			||||||
 | 
					    private var internalValue: T = initial
 | 
				
			||||||
 | 
					    override var value: T
 | 
				
			||||||
 | 
					        get() = internalValue
 | 
				
			||||||
 | 
					        set(value) {
 | 
				
			||||||
 | 
					            internalValue = value
 | 
				
			||||||
 | 
					            tryEmit(value)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onChangeWithoutSync(value: T) {
 | 
				
			||||||
 | 
					        internalValue = value
 | 
				
			||||||
 | 
					        super.onChangeWithoutSync(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun component1(): T = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun component2(): (T) -> Unit = { tryEmit(it) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun tryEmit(value: T): Boolean {
 | 
				
			||||||
 | 
					        internalValue = value
 | 
				
			||||||
 | 
					        return super.tryEmit(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun emit(value: T) {
 | 
				
			||||||
 | 
					        internalValue = value
 | 
				
			||||||
 | 
					        super.emit(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//fun <T> MutableState<T>.asFlowState(scope: CoroutineScope = CoroutineScope(Dispatchers.Main)) = FlowState(this, scope)
 | 
				
			||||||
@@ -23,6 +23,7 @@ class SmartRWLocker(private val readPermits: Int = Int.MAX_VALUE, writeIsLocked:
 | 
				
			|||||||
     * Do lock in [readSemaphore] inside of [writeMutex] locking
 | 
					     * Do lock in [readSemaphore] inside of [writeMutex] locking
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    suspend fun acquireRead() {
 | 
					    suspend fun acquireRead() {
 | 
				
			||||||
 | 
					        _writeMutex.waitUnlock()
 | 
				
			||||||
        _readSemaphore.acquire()
 | 
					        _readSemaphore.acquire()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
				
			||||||
 | 
					import kotlinx.coroutines.InternalCoroutinesApi
 | 
				
			||||||
 | 
					import kotlinx.coroutines.channels.BufferOverflow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.FlowCollector
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.MutableSharedFlow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.MutableStateFlow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.StateFlow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.internal.SynchronizedObject
 | 
				
			||||||
 | 
					import kotlinx.coroutines.internal.synchronized
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Works like [StateFlow], but guarantee that latest value update will always be delivered to
 | 
				
			||||||
 | 
					 * each active subscriber
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					open class SpecialMutableStateFlow<T>(
 | 
				
			||||||
 | 
					    initialValue: T,
 | 
				
			||||||
 | 
					    internalScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
				
			||||||
 | 
					) : MutableStateFlow<T>, FlowCollector<T>, MutableSharedFlow<T> {
 | 
				
			||||||
 | 
					    @OptIn(InternalCoroutinesApi::class)
 | 
				
			||||||
 | 
					    private val syncObject = SynchronizedObject()
 | 
				
			||||||
 | 
					    protected val internalSharedFlow: MutableSharedFlow<T> = MutableSharedFlow(
 | 
				
			||||||
 | 
					        replay = 0,
 | 
				
			||||||
 | 
					        extraBufferCapacity = 2,
 | 
				
			||||||
 | 
					        onBufferOverflow = BufferOverflow.DROP_OLDEST
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    protected val publicSharedFlow: MutableSharedFlow<T> = MutableSharedFlow(
 | 
				
			||||||
 | 
					        replay = 1,
 | 
				
			||||||
 | 
					        extraBufferCapacity = 1,
 | 
				
			||||||
 | 
					        onBufferOverflow = BufferOverflow.DROP_OLDEST
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected var _value: T = initialValue
 | 
				
			||||||
 | 
					    override var value: T
 | 
				
			||||||
 | 
					        get() = _value
 | 
				
			||||||
 | 
					        set(value) {
 | 
				
			||||||
 | 
					            doOnChangeAction(value)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    protected val job = internalSharedFlow.subscribe(internalScope) {
 | 
				
			||||||
 | 
					        doOnChangeAction(it)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val replayCache: List<T>
 | 
				
			||||||
 | 
					        get() = publicSharedFlow.replayCache
 | 
				
			||||||
 | 
					    override val subscriptionCount: StateFlow<Int>
 | 
				
			||||||
 | 
					        get() = publicSharedFlow.subscriptionCount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @OptIn(InternalCoroutinesApi::class)
 | 
				
			||||||
 | 
					    override fun compareAndSet(expect: T, update: T): Boolean {
 | 
				
			||||||
 | 
					        return synchronized(syncObject) {
 | 
				
			||||||
 | 
					            if (expect == _value && update != _value) {
 | 
				
			||||||
 | 
					                doOnChangeAction(update)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            expect == _value
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected open fun onChangeWithoutSync(value: T) {
 | 
				
			||||||
 | 
					        _value = value
 | 
				
			||||||
 | 
					        publicSharedFlow.tryEmit(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    @OptIn(InternalCoroutinesApi::class)
 | 
				
			||||||
 | 
					    protected open fun doOnChangeAction(value: T) {
 | 
				
			||||||
 | 
					        synchronized(syncObject) {
 | 
				
			||||||
 | 
					            if (_value != value) {
 | 
				
			||||||
 | 
					                onChangeWithoutSync(value)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @ExperimentalCoroutinesApi
 | 
				
			||||||
 | 
					    override fun resetReplayCache() = publicSharedFlow.resetReplayCache()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun tryEmit(value: T): Boolean {
 | 
				
			||||||
 | 
					        return internalSharedFlow.tryEmit(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun emit(value: T) {
 | 
				
			||||||
 | 
					        internalSharedFlow.emit(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun collect(collector: FlowCollector<T>) = publicSharedFlow.collect(collector)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -27,7 +27,7 @@ android {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    compileOptions {
 | 
					    compileOptions {
 | 
				
			||||||
        sourceCompatibility JavaVersion.VERSION_1_8
 | 
					        sourceCompatibility JavaVersion.VERSION_17
 | 
				
			||||||
        targetCompatibility JavaVersion.VERSION_1_8
 | 
					        targetCompatibility JavaVersion.VERSION_17
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,13 +18,13 @@ if (new File(projectDir, "secret.gradle").exists()) {
 | 
				
			|||||||
    githubRelease {
 | 
					    githubRelease {
 | 
				
			||||||
        token "${project.property('GITHUB_RELEASE_TOKEN')}"
 | 
					        token "${project.property('GITHUB_RELEASE_TOKEN')}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        owner "InsanusMokrassar"
 | 
					        owner = "InsanusMokrassar"
 | 
				
			||||||
        repo "MicroUtils"
 | 
					        repo = "MicroUtils"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        tagName "v${project.version}"
 | 
					        tagName = "v${project.version}"
 | 
				
			||||||
        releaseName "${project.version}"
 | 
					        releaseName = "${project.version}"
 | 
				
			||||||
        targetCommitish "${project.version}"
 | 
					        targetCommitish = "${project.version}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        body getCurrentVersionChangelog()
 | 
					        body = getCurrentVersionChangelog()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ kotlin.incremental.js=true
 | 
				
			|||||||
#kotlin.experimental.tryK2=true
 | 
					#kotlin.experimental.tryK2=true
 | 
				
			||||||
android.useAndroidX=true
 | 
					android.useAndroidX=true
 | 
				
			||||||
android.enableJetifier=true
 | 
					android.enableJetifier=true
 | 
				
			||||||
org.gradle.jvmargs=-Xmx2500m
 | 
					org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=2g
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# JS NPM
 | 
					# JS NPM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,5 +15,5 @@ crypto_js_version=4.1.1
 | 
				
			|||||||
# Project data
 | 
					# Project data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group=dev.inmo
 | 
					group=dev.inmo
 | 
				
			||||||
version=0.20.10
 | 
					version=0.20.40
 | 
				
			||||||
android_code_version=216
 | 
					android_code_version=246
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,42 +1,41 @@
 | 
				
			|||||||
[versions]
 | 
					[versions]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
kt = "1.9.20-RC2"
 | 
					kt = "1.9.23"
 | 
				
			||||||
#compose-kotlin = "1.5.10-beta02"
 | 
					kt-serialization = "1.6.3"
 | 
				
			||||||
kt-serialization = "1.6.0"
 | 
					kt-coroutines = "1.8.0"
 | 
				
			||||||
kt-coroutines = "1.7.3"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
kslog = "1.2.2"
 | 
					kslog = "1.3.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jb-compose = "1.5.10-rc02"
 | 
					jb-compose = "1.6.1"
 | 
				
			||||||
jb-exposed = "0.44.0"
 | 
					jb-exposed = "0.49.0"
 | 
				
			||||||
jb-dokka = "1.9.10"
 | 
					jb-dokka = "1.9.20"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
korlibs = "4.0.10"
 | 
					korlibs = "5.4.0"
 | 
				
			||||||
uuid = "0.8.1"
 | 
					uuid = "0.8.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ktor = "2.3.5"
 | 
					ktor = "2.3.9"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gh-release = "2.4.1"
 | 
					gh-release = "2.5.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
koin = "3.5.0"
 | 
					koin = "3.5.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
okio = "3.6.0"
 | 
					okio = "3.9.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ksp = "1.9.20-RC2-1.0.13"
 | 
					ksp = "1.9.23-1.0.19"
 | 
				
			||||||
kotlin-poet = "1.14.2"
 | 
					kotlin-poet = "1.16.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
versions = "0.49.0"
 | 
					versions = "0.51.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android-gradle = "7.4.2"
 | 
					android-gradle = "8.3.1"
 | 
				
			||||||
dexcount = "4.0.0"
 | 
					dexcount = "4.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android-coreKtx = "1.12.0"
 | 
					android-coreKtx = "1.12.0"
 | 
				
			||||||
android-recyclerView = "1.3.2"
 | 
					android-recyclerView = "1.3.2"
 | 
				
			||||||
android-appCompat = "1.6.1"
 | 
					android-appCompat = "1.6.1"
 | 
				
			||||||
android-fragment = "1.6.1"
 | 
					android-fragment = "1.6.2"
 | 
				
			||||||
android-espresso = "3.5.1"
 | 
					android-espresso = "3.5.1"
 | 
				
			||||||
android-test = "1.1.5"
 | 
					android-test = "1.1.5"
 | 
				
			||||||
android-compose-material3 = "1.1.2"
 | 
					android-compose-material3 = "1.2.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android-props-minSdk = "21"
 | 
					android-props-minSdk = "21"
 | 
				
			||||||
android-props-compileSdk = "34"
 | 
					android-props-compileSdk = "34"
 | 
				
			||||||
@@ -73,8 +72,8 @@ ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negoti
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
 | 
					kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "korlibs" }
 | 
					klock = { module = "com.soywiz.korge:korlibs-time", version.ref = "korlibs" }
 | 
				
			||||||
krypto = { module = "com.soywiz.korlibs.krypto:krypto", version.ref = "korlibs" }
 | 
					krypto = { module = "com.soywiz.korge:korlibs-crypto", version.ref = "korlibs" }
 | 
				
			||||||
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
 | 
					uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
 | 
				
			||||||
koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }
 | 
					koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
distributionBase=GRADLE_USER_HOME
 | 
					distributionBase=GRADLE_USER_HOME
 | 
				
			||||||
distributionPath=wrapper/dists
 | 
					distributionPath=wrapper/dists
 | 
				
			||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-bin.zip
 | 
					distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
 | 
				
			||||||
zipStoreBase=GRADLE_USER_HOME
 | 
					zipStoreBase=GRADLE_USER_HOME
 | 
				
			||||||
zipStorePath=wrapper/dists
 | 
					zipStorePath=wrapper/dists
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,11 @@ apply plugin: 'maven-publish'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
task javadocJar(type: Jar) {
 | 
					task javadocJar(type: Jar) {
 | 
				
			||||||
    from javadoc
 | 
					    from javadoc
 | 
				
			||||||
    classifier = 'javadoc'
 | 
					    archiveClassifier = 'javadoc'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
task sourcesJar(type: Jar) {
 | 
					task sourcesJar(type: Jar) {
 | 
				
			||||||
    from sourceSets.main.allSource
 | 
					    from sourceSets.main.allSource
 | 
				
			||||||
    classifier = 'sources'
 | 
					    archiveClassifier = 'sources'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
publishing {
 | 
					publishing {
 | 
				
			||||||
@@ -68,18 +68,14 @@ publishing {
 | 
				
			|||||||
                
 | 
					                
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
 | 
					                if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
 | 
				
			||||||
                    maven {
 | 
					                    maven {
 | 
				
			||||||
                        name = "Gitea"
 | 
					                        name = "InmoNexus"
 | 
				
			||||||
                        url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
 | 
					                        url = uri("https://nexus.inmo.dev/repository/maven-releases/")
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                        credentials(HttpHeaderCredentials) {
 | 
					                        credentials {
 | 
				
			||||||
                            name = "Authorization"
 | 
					                            username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
 | 
				
			||||||
                            value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
 | 
					                            password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                        authentication {
 | 
					 | 
				
			||||||
                            header(HttpHeaderAuthentication)
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@@ -115,4 +111,27 @@ if (project.hasProperty("signing.gnupg.keyName")) {
 | 
				
			|||||||
            dependsOn(it)
 | 
					            dependsOn(it)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Workaround to make android sign operations depend on signing tasks
 | 
				
			||||||
 | 
					    project.getTasks().withType(AbstractPublishToMaven.class).configureEach {
 | 
				
			||||||
 | 
					        def signingTasks = project.getTasks().withType(Sign.class)
 | 
				
			||||||
 | 
					        mustRunAfter(signingTasks)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Workaround to make test tasks use sign
 | 
				
			||||||
 | 
					    project.getTasks().withType(Sign.class).configureEach { signTask ->
 | 
				
			||||||
 | 
					        def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name)
 | 
				
			||||||
 | 
					        def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign
 | 
				
			||||||
 | 
					        // These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
 | 
				
			||||||
 | 
					        def debugTestTask = tasks.findByName("linkDebugTest$pubName")
 | 
				
			||||||
 | 
					        if (debugTestTask != null) {
 | 
				
			||||||
 | 
					            signTask.mustRunAfter(debugTestTask)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
 | 
				
			||||||
 | 
					        def testTask = tasks.findByName("compileTestKotlin$pubName")
 | 
				
			||||||
 | 
					        if (testTask != null) {
 | 
				
			||||||
 | 
					            signTask.mustRunAfter(testTask)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"Gitea","url":"https://git.inmo.dev/api/packages/InsanusMokrassar/maven","credsType":{"type":"dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository.CredentialsType.HttpHeaderCredentials","headerName":"Authorization","headerValueProperty":"GITEA_TOKEN"}},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}},"type":"JVM"}
 | 
					{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}},"type":"JVM"}
 | 
				
			||||||
@@ -15,6 +15,6 @@ dependencies {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,6 @@ dependencies {
 | 
				
			|||||||
mainClassName="MainKt"
 | 
					mainClassName="MainKt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,9 +12,12 @@ private val json = Json {
 | 
				
			|||||||
    ignoreUnknownKeys = true
 | 
					    ignoreUnknownKeys = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private const val baseClassName = "IetfLanguageCode"
 | 
					private const val baseClassName = "IetfLang"
 | 
				
			||||||
 | 
					private const val oldBaseClassName = "IetfLanguageCode"
 | 
				
			||||||
private const val unknownBaseClassName = "Unknown$baseClassName"
 | 
					private const val unknownBaseClassName = "Unknown$baseClassName"
 | 
				
			||||||
private const val baseClassSerializerName = "IetfLanguageCodeSerializer"
 | 
					private const val oldUnknownBaseClassName = "Unknown$oldBaseClassName"
 | 
				
			||||||
 | 
					private const val baseClassSerializerName = "${baseClassName}Serializer"
 | 
				
			||||||
 | 
					private const val oldBaseClassSerializerName = "IetfLanguageCodeSerializer"
 | 
				
			||||||
private const val baseClassSerializerAnnotationName = "@Serializable(${baseClassSerializerName}::class)"
 | 
					private const val baseClassSerializerAnnotationName = "@Serializable(${baseClassSerializerName}::class)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
@@ -78,14 +81,12 @@ private fun printLanguageCodeAndTags(
 | 
				
			|||||||
    indents: String = "    "
 | 
					    indents: String = "    "
 | 
				
			||||||
): String = if (tag.subtags.isEmpty()) {
 | 
					): String = if (tag.subtags.isEmpty()) {
 | 
				
			||||||
"""${indents}${baseClassSerializerAnnotationName}
 | 
					"""${indents}${baseClassSerializerAnnotationName}
 | 
				
			||||||
${indents}object ${tag.title} : ${parent ?.title ?: baseClassName}() { override val code: String = "${tag.tag}"; override val withoutDialect: String get() = ${parent ?.title ?.let { "$it.code" } ?: "code"} }"""
 | 
					${indents}object ${tag.title} : ${parent ?.title ?: baseClassName}() { override val code: String = "${tag.tag}"${parent ?.let { parent -> "; override val parentLang: ${parent.title} get() = ${parent.title};" } ?: ""} }"""
 | 
				
			||||||
} else {
 | 
					} else {
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
${indents}${baseClassSerializerAnnotationName}
 | 
					${indents}${baseClassSerializerAnnotationName}
 | 
				
			||||||
${indents}sealed class ${tag.title} : ${parent ?.title ?: baseClassName}() {
 | 
					${indents}sealed class ${tag.title} : ${parent ?.title ?: baseClassName}() {
 | 
				
			||||||
${indents}    override val code: String = "${tag.tag}"
 | 
					${indents}    override val code: String = "${tag.tag}"${parent ?.let { parent -> "\n${indents}    override val parentLang: ${parent.title} get() = ${parent.title};" } ?: ""}
 | 
				
			||||||
${indents}    override val withoutDialect: String
 | 
					 | 
				
			||||||
${indents}        get() = code
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
${tag.subtags.joinToString("\n") { printLanguageCodeAndTags(it, tag, "${indents}    ") }}
 | 
					${tag.subtags.joinToString("\n") { printLanguageCodeAndTags(it, tag, "${indents}    ") }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,7 +96,7 @@ ${indents}}
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun buildKtFileContent(tags: List<Tag>): String = """
 | 
					fun buildKtFileContent(tags: List<Tag>, prePackage: String): String = """
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -106,20 +107,27 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
${baseClassSerializerAnnotationName}
 | 
					${baseClassSerializerAnnotationName}
 | 
				
			||||||
sealed class $baseClassName {
 | 
					sealed class $baseClassName {
 | 
				
			||||||
    abstract val code: String
 | 
					    abstract val code: String
 | 
				
			||||||
    abstract val withoutDialect: String
 | 
					    open val parentLang: $baseClassName?
 | 
				
			||||||
 | 
					        get() = null
 | 
				
			||||||
 | 
					    open val withoutDialect: String
 | 
				
			||||||
 | 
					        get() = parentLang ?.code ?: code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
${tags.joinToString("\n") { printLanguageCodeAndTags(it, indents = "    ") } }
 | 
					${tags.joinToString("\n") { printLanguageCodeAndTags(it, indents = "    ") } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $baseClassSerializerAnnotationName
 | 
					    $baseClassSerializerAnnotationName
 | 
				
			||||||
    data class $unknownBaseClassName (override val code: String) : $baseClassName() {
 | 
					    data class $unknownBaseClassName (override val code: String) : $baseClassName() {
 | 
				
			||||||
        override val withoutDialect: String = code.takeWhile { it != '-' }
 | 
					        override val parentLang = code.dropLastWhile { it != '-' }.removeSuffix("-").takeIf { it.length > 0 } ?.let(::$unknownBaseClassName)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    @Deprecated("Renamed", ReplaceWith("$baseClassName.$unknownBaseClassName", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}$baseClassName.$unknownBaseClassName"))
 | 
				
			||||||
 | 
					    val $oldUnknownBaseClassName = $unknownBaseClassName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun toString() = code
 | 
					    override fun toString() = code
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("$baseClassName", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}$baseClassName"))
 | 
				
			||||||
 | 
					typealias $oldBaseClassName = $baseClassName
 | 
				
			||||||
""".trimIndent()
 | 
					""".trimIndent()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun createStringConverterCode(tags: List<Tag>): String {
 | 
					fun createStringConverterCode(tags: List<Tag>, prePackage: String): String {
 | 
				
			||||||
    fun createDeserializeVariantForTag(
 | 
					    fun createDeserializeVariantForTag(
 | 
				
			||||||
        tag: Tag,
 | 
					        tag: Tag,
 | 
				
			||||||
        pretitle: String = baseClassName,
 | 
					        pretitle: String = baseClassName,
 | 
				
			||||||
@@ -128,19 +136,70 @@ fun createStringConverterCode(tags: List<Tag>): String {
 | 
				
			|||||||
        val currentTitle = "$pretitle.${tag.title}"
 | 
					        val currentTitle = "$pretitle.${tag.title}"
 | 
				
			||||||
        return """${indents}$currentTitle.code -> $currentTitle${if (tag.subtags.isNotEmpty()) tag.subtags.joinToString("\n", "\n") { createDeserializeVariantForTag(it, currentTitle, indents) } else ""}"""
 | 
					        return """${indents}$currentTitle.code -> $currentTitle${if (tag.subtags.isNotEmpty()) tag.subtags.joinToString("\n", "\n") { createDeserializeVariantForTag(it, currentTitle, indents) } else ""}"""
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fun createInheritorVariantForTag(
 | 
				
			||||||
    return """fun String.as$baseClassName(): $baseClassName {
 | 
					        tag: Tag,
 | 
				
			||||||
    return when (this) {
 | 
					        pretitle: String = baseClassName,
 | 
				
			||||||
${tags.joinToString("\n") { createDeserializeVariantForTag(it) }}
 | 
					        indents: String = "        "
 | 
				
			||||||
        else -> $baseClassName.${unknownBaseClassName}(this)
 | 
					    ): String {
 | 
				
			||||||
 | 
					        val currentTitle = "$pretitle.${tag.title}"
 | 
				
			||||||
 | 
					        val subtags = if (tag.subtags.isNotEmpty()) {
 | 
				
			||||||
 | 
					            tag.subtags.joinToString(",\n", ",\n") { createInheritorVariantForTag(it, currentTitle, "$indents    ") }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ""
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "${indents}$currentTitle$subtags"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fun createInheritorVariantForMapForTag(
 | 
				
			||||||
 | 
					        tag: Tag,
 | 
				
			||||||
 | 
					        pretitle: String = baseClassName,
 | 
				
			||||||
 | 
					        indents: String = "        ",
 | 
				
			||||||
 | 
					        codeSuffix: String = ""
 | 
				
			||||||
 | 
					    ): String {
 | 
				
			||||||
 | 
					        val currentTitle = "$pretitle.${tag.title}"
 | 
				
			||||||
 | 
					        val subtags = if (tag.subtags.isNotEmpty()) {
 | 
				
			||||||
 | 
					            tag.subtags.joinToString(",\n", ",\n") { createInheritorVariantForMapForTag(it, currentTitle, "$indents    ", codeSuffix) }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ""
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "${indents}$currentTitle.code${codeSuffix} to $currentTitle$subtags"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return """val knownLanguageCodesMap: Map<String, $baseClassName> by lazy {
 | 
				
			||||||
 | 
					    mapOf(
 | 
				
			||||||
 | 
					${tags.joinToString(",\n") { createInheritorVariantForMapForTag(it, indents = "        ") }}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					val knownLanguageCodesMapByLowerCasedKeys: Map<String, $baseClassName> by lazy {
 | 
				
			||||||
 | 
					    mapOf(
 | 
				
			||||||
 | 
					${tags.joinToString(",\n") { createInheritorVariantForMapForTag(it, indents = "        ", codeSuffix = ".lowercase()") }}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					val knownLanguageCodes: List<$baseClassName> by lazy {
 | 
				
			||||||
 | 
					    knownLanguageCodesMap.values.toList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun String.as$baseClassName(): $baseClassName {
 | 
				
			||||||
 | 
					    return knownLanguageCodesMap[this] ?: $baseClassName.${unknownBaseClassName}(this)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					fun String.as${baseClassName}CaseInsensitive(): $baseClassName {
 | 
				
			||||||
 | 
					    return knownLanguageCodesMapByLowerCasedKeys[this.lowercase()] ?: $baseClassName.${unknownBaseClassName}(this)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("this.as$baseClassName()", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}as$baseClassName"))
 | 
				
			||||||
 | 
					fun String.as$oldBaseClassName(): $baseClassName = as$baseClassName()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun convertTo$baseClassName(code: String) = code.as$baseClassName()
 | 
					fun convertTo$baseClassName(code: String) = code.as$baseClassName()
 | 
				
			||||||
 | 
					fun convertTo${baseClassName}CaseInsensitive(code: String) = code.as${baseClassName}CaseInsensitive()
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("convertTo$baseClassName(code)", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}convertTo$baseClassName"))
 | 
				
			||||||
 | 
					fun convertTo$oldBaseClassName(code: String) = convertTo$baseClassName(code)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun $baseClassName(code: String) = code.as$baseClassName()
 | 
					fun $baseClassName(code: String) = code.as$baseClassName()
 | 
				
			||||||
 | 
					fun ${baseClassName}CaseInsensitive(code: String) = code.as${baseClassName}CaseInsensitive()
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("$baseClassName(code)", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}$baseClassName"))
 | 
				
			||||||
 | 
					fun $oldBaseClassName(code: String) = $baseClassName(code)
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun createSerializerCode(tags: List<Tag>): String {
 | 
					fun createSerializerCode(tags: List<Tag>, prePackage: String): String {
 | 
				
			||||||
    return """import kotlinx.serialization.KSerializer
 | 
					    return """import kotlinx.serialization.KSerializer
 | 
				
			||||||
import kotlinx.serialization.builtins.serializer
 | 
					import kotlinx.serialization.builtins.serializer
 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					import kotlinx.serialization.encoding.Decoder
 | 
				
			||||||
@@ -153,16 +212,20 @@ object $baseClassSerializerName : KSerializer<$baseClassName> {
 | 
				
			|||||||
        return $baseClassName(decoder.decodeString())
 | 
					        return $baseClassName(decoder.decodeString())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun serialize(encoder: Encoder, value: IetfLanguageCode) {
 | 
					    override fun serialize(encoder: Encoder, value: $baseClassName) {
 | 
				
			||||||
        encoder.encodeString(value.code)
 | 
					        encoder.encodeString(value.code)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("$baseClassSerializerName", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}$baseClassSerializerName"))
 | 
				
			||||||
 | 
					typealias $oldBaseClassSerializerName = $baseClassSerializerName
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend fun main(vararg args: String) {
 | 
					suspend fun main(vararg args: String) {
 | 
				
			||||||
    val outputFolder = args.firstOrNull() ?.let { File(it) }
 | 
					    val outputFolder = args.firstOrNull() ?.let { File(it) }
 | 
				
			||||||
    outputFolder ?.mkdirs()
 | 
					    outputFolder ?.mkdirs()
 | 
				
			||||||
 | 
					    val targetPackage = args.getOrNull(1)
 | 
				
			||||||
 | 
					    val targetPackagePrefix = targetPackage ?.let { "package $it\n\n" } ?: ""
 | 
				
			||||||
    val ietfLanguageCodesLink = "https://datahub.io/core/language-codes/r/language-codes.json"
 | 
					    val ietfLanguageCodesLink = "https://datahub.io/core/language-codes/r/language-codes.json"
 | 
				
			||||||
    val ietfLanguageCodesAdditionalTagsLink = "https://datahub.io/core/language-codes/r/ietf-language-tags.json"
 | 
					    val ietfLanguageCodesAdditionalTagsLink = "https://datahub.io/core/language-codes/r/ietf-language-tags.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,18 +266,18 @@ suspend fun main(vararg args: String) {
 | 
				
			|||||||
    File(outputFolder, "LanguageCodes.kt").apply {
 | 
					    File(outputFolder, "LanguageCodes.kt").apply {
 | 
				
			||||||
        delete()
 | 
					        delete()
 | 
				
			||||||
        createNewFile()
 | 
					        createNewFile()
 | 
				
			||||||
        writeText(buildKtFileContent(tags))
 | 
					        writeText(targetPackagePrefix + buildKtFileContent(tags, targetPackage ?: ""))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    File(outputFolder, "StringToLanguageCodes.kt").apply {
 | 
					    File(outputFolder, "StringToLanguageCodes.kt").apply {
 | 
				
			||||||
        delete()
 | 
					        delete()
 | 
				
			||||||
        createNewFile()
 | 
					        createNewFile()
 | 
				
			||||||
        writeText(createStringConverterCode(tags))
 | 
					        writeText(targetPackagePrefix + createStringConverterCode(tags, targetPackage ?: ""))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    File(outputFolder, "$baseClassSerializerName.kt").apply {
 | 
					    File(outputFolder, "$baseClassSerializerName.kt").apply {
 | 
				
			||||||
        delete()
 | 
					        delete()
 | 
				
			||||||
        createNewFile()
 | 
					        createNewFile()
 | 
				
			||||||
        writeText(createSerializerCode(tags))
 | 
					        writeText(targetPackagePrefix + createSerializerCode(tags, targetPackage ?: ""))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.language_codes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.KSerializer
 | 
				
			||||||
 | 
					import kotlinx.serialization.builtins.serializer
 | 
				
			||||||
 | 
					import kotlinx.serialization.encoding.Decoder
 | 
				
			||||||
 | 
					import kotlinx.serialization.encoding.Encoder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object IetfLangSerializer : KSerializer<IetfLang> {
 | 
				
			||||||
 | 
					    override val descriptor = String.serializer().descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun deserialize(decoder: Decoder): IetfLang {
 | 
				
			||||||
 | 
					        return IetfLang(decoder.decodeString())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun serialize(encoder: Encoder, value: IetfLang) {
 | 
				
			||||||
 | 
					        encoder.encodeString(value.code)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("IetfLangSerializer", "dev.inmo.micro_utils.language_codes.IetfLangSerializer"))
 | 
				
			||||||
 | 
					typealias IetfLanguageCodeSerializer = IetfLangSerializer
 | 
				
			||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.language_codes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import kotlinx.serialization.KSerializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.builtins.serializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					 | 
				
			||||||
import kotlinx.serialization.encoding.Encoder
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
object IetfLanguageCodeSerializer : KSerializer<IetfLanguageCode> {
 | 
					 | 
				
			||||||
    override val descriptor = String.serializer().descriptor
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun deserialize(decoder: Decoder): IetfLanguageCode {
 | 
					 | 
				
			||||||
        return IetfLanguageCode(decoder.decodeString())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun serialize(encoder: Encoder, value: IetfLanguageCode) {
 | 
					 | 
				
			||||||
        encoder.encodeString(value.code)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.language_codes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlin.test.Test
 | 
				
			||||||
 | 
					import kotlin.test.assertEquals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UnknownIetfLanguageTests {
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun commonTestOfParentCode() {
 | 
				
			||||||
 | 
					        knownLanguageCodes.forEach {
 | 
				
			||||||
 | 
					            val language = IetfLang.UnknownIetfLang(it.code)
 | 
				
			||||||
 | 
					            assertEquals(it.code, language.code)
 | 
				
			||||||
 | 
					            assertEquals(it.withoutDialect, language.withoutDialect)
 | 
				
			||||||
 | 
					            assertEquals(it.parentLang ?.code, language.parentLang ?.code)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,7 +2,9 @@ package dev.inmo.micro_utils.language_codes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.util.Locale
 | 
					import java.util.Locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun IetfLanguageCode.toJavaLocale(): Locale = Locale.forLanguageTag(code)
 | 
					fun IetfLang.toJavaLocale(): Locale = Locale.forLanguageTag(code)
 | 
				
			||||||
fun IetfLanguageCode?.toJavaLocaleOrDefault(): Locale = this ?.toJavaLocale() ?: Locale.getDefault()
 | 
					fun IetfLang?.toJavaLocaleOrDefault(): Locale = this?.toJavaLocale() ?: Locale.getDefault()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun Locale.toIetfLanguageCode(): IetfLanguageCode = IetfLanguageCode(toLanguageTag())
 | 
					fun Locale.toIetfLang(): IetfLang = IetfLang(toLanguageTag())
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("this.toIetfLang()", "dev.inmo.micro_utils.language_codes.toIetfLang"))
 | 
				
			||||||
 | 
					fun Locale.toIetfLanguageCode(): IetfLang = toIetfLang()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,15 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.matrix
 | 
					package dev.inmo.micro_utils.matrix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MatrixBuilder<T> {
 | 
					open class MatrixBuilder<T> {
 | 
				
			||||||
    private val mutMatrix: MutableList<List<T>> = ArrayList()
 | 
					    private val mutMatrix: MutableList<List<T>> = ArrayList()
 | 
				
			||||||
    val matrix: Matrix<T>
 | 
					    val matrix: Matrix<T>
 | 
				
			||||||
        get() = mutMatrix
 | 
					        get() = mutMatrix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun row(t: List<T>) = mutMatrix.add(t)
 | 
					    fun row(t: List<T>) = mutMatrix.add(t)
 | 
				
			||||||
 | 
					    fun add(t: List<T>) = mutMatrix.add(t)
 | 
				
			||||||
    operator fun List<T>.unaryPlus() = row(this)
 | 
					    operator fun List<T>.unaryPlus() = row(this)
 | 
				
			||||||
 | 
					    operator fun plus(t: List<T>) = add(t)
 | 
				
			||||||
 | 
					    operator fun T.unaryPlus() = add(listOf(this))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <T> MatrixBuilder<T>.row(block: RowBuilder<T>.() -> Unit) = +RowBuilder<T>().also(block).row
 | 
					fun <T> MatrixBuilder<T>.row(block: RowBuilder<T>.() -> Unit) = +RowBuilder<T>().also(block).row
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,13 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.matrix
 | 
					package dev.inmo.micro_utils.matrix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RowBuilder<T> {
 | 
					open class RowBuilder<T> {
 | 
				
			||||||
    private val mutRow: MutableList<T> = ArrayList()
 | 
					    private val mutRow: MutableList<T> = ArrayList()
 | 
				
			||||||
    val row: Row<T>
 | 
					    val row: Row<T>
 | 
				
			||||||
        get() = mutRow
 | 
					        get() = mutRow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun column(t: T) = mutRow.add(t)
 | 
					    fun add(t: T) = mutRow.add(t)
 | 
				
			||||||
    operator fun T.unaryPlus() = column(this)
 | 
					    operator fun T.unaryPlus() = column(this)
 | 
				
			||||||
 | 
					    fun column(t: T) = mutRow.add(t)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <T> row(block: RowBuilder<T>.() -> Unit): List<T> = RowBuilder<T>().also(block).row
 | 
					fun <T> row(block: RowBuilder<T>.() -> Unit): List<T> = RowBuilder<T>().also(block).row
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,11 @@ apply from: "$publishGradlePath"
 | 
				
			|||||||
kotlin {
 | 
					kotlin {
 | 
				
			||||||
    androidTarget {
 | 
					    androidTarget {
 | 
				
			||||||
        publishAllLibraryVariants()
 | 
					        publishAllLibraryVariants()
 | 
				
			||||||
 | 
					        compilations.all {
 | 
				
			||||||
 | 
					            kotlinOptions {
 | 
				
			||||||
 | 
					                jvmTarget = "17"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sourceSets {
 | 
					    sourceSets {
 | 
				
			||||||
@@ -27,6 +32,6 @@ kotlin {
 | 
				
			|||||||
apply from: "$defaultAndroidSettingsPresetPath"
 | 
					apply from: "$defaultAndroidSettingsPresetPath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ kotlin {
 | 
				
			|||||||
    jvm {
 | 
					    jvm {
 | 
				
			||||||
        compilations.main {
 | 
					        compilations.main {
 | 
				
			||||||
            kotlinOptions {
 | 
					            kotlinOptions {
 | 
				
			||||||
                jvmTarget = "1.8"
 | 
					                jvmTarget = "17"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -35,6 +35,6 @@ kotlin {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ kotlin {
 | 
				
			|||||||
    jvm {
 | 
					    jvm {
 | 
				
			||||||
        compilations.main {
 | 
					        compilations.main {
 | 
				
			||||||
            kotlinOptions {
 | 
					            kotlinOptions {
 | 
				
			||||||
                jvmTarget = "1.8"
 | 
					                jvmTarget = "17"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -17,6 +17,11 @@ kotlin {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    androidTarget {
 | 
					    androidTarget {
 | 
				
			||||||
        publishAllLibraryVariants()
 | 
					        publishAllLibraryVariants()
 | 
				
			||||||
 | 
					        compilations.all {
 | 
				
			||||||
 | 
					            kotlinOptions {
 | 
				
			||||||
 | 
					                jvmTarget = "17"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    linuxX64()
 | 
					    linuxX64()
 | 
				
			||||||
    mingwX64()
 | 
					    mingwX64()
 | 
				
			||||||
@@ -61,6 +66,6 @@ kotlin {
 | 
				
			|||||||
apply from: "$defaultAndroidSettingsPresetPath"
 | 
					apply from: "$defaultAndroidSettingsPresetPath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ kotlin {
 | 
				
			|||||||
    jvm {
 | 
					    jvm {
 | 
				
			||||||
        compilations.main {
 | 
					        compilations.main {
 | 
				
			||||||
            kotlinOptions {
 | 
					            kotlinOptions {
 | 
				
			||||||
                jvmTarget = "1.8"
 | 
					                jvmTarget = "17"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -17,6 +17,11 @@ kotlin {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    androidTarget {
 | 
					    androidTarget {
 | 
				
			||||||
        publishAllLibraryVariants()
 | 
					        publishAllLibraryVariants()
 | 
				
			||||||
 | 
					        compilations.all {
 | 
				
			||||||
 | 
					            kotlinOptions {
 | 
				
			||||||
 | 
					                jvmTarget = "17"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    linuxX64()
 | 
					    linuxX64()
 | 
				
			||||||
    mingwX64()
 | 
					    mingwX64()
 | 
				
			||||||
@@ -71,6 +76,6 @@ kotlin {
 | 
				
			|||||||
apply from: "$defaultAndroidSettingsPresetPath"
 | 
					apply from: "$defaultAndroidSettingsPresetPath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ kotlin {
 | 
				
			|||||||
    jvm {
 | 
					    jvm {
 | 
				
			||||||
        compilations.main {
 | 
					        compilations.main {
 | 
				
			||||||
            kotlinOptions {
 | 
					            kotlinOptions {
 | 
				
			||||||
                jvmTarget = "1.8"
 | 
					                jvmTarget = "17"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -49,6 +49,6 @@ kotlin {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ kotlin {
 | 
				
			|||||||
    jvm {
 | 
					    jvm {
 | 
				
			||||||
        compilations.main {
 | 
					        compilations.main {
 | 
				
			||||||
            kotlinOptions {
 | 
					            kotlinOptions {
 | 
				
			||||||
                jvmTarget = "1.8"
 | 
					                jvmTarget = "17"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -60,6 +60,6 @@ kotlin {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ kotlin {
 | 
				
			|||||||
    jvm {
 | 
					    jvm {
 | 
				
			||||||
        compilations.main {
 | 
					        compilations.main {
 | 
				
			||||||
            kotlinOptions {
 | 
					            kotlinOptions {
 | 
				
			||||||
                jvmTarget = "1.8"
 | 
					                jvmTarget = "17"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -17,6 +17,11 @@ kotlin {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    androidTarget {
 | 
					    androidTarget {
 | 
				
			||||||
        publishAllLibraryVariants()
 | 
					        publishAllLibraryVariants()
 | 
				
			||||||
 | 
					        compilations.all {
 | 
				
			||||||
 | 
					            kotlinOptions {
 | 
				
			||||||
 | 
					                jvmTarget = "17"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sourceSets {
 | 
					    sourceSets {
 | 
				
			||||||
@@ -70,8 +75,8 @@ kotlin {
 | 
				
			|||||||
apply from: "$defaultAndroidSettingsPresetPath"
 | 
					apply from: "$defaultAndroidSettingsPresetPath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
apply plugin: 'maven-publish'
 | 
					apply plugin: 'maven-publish'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
task javadocsJar(type: Jar) {
 | 
					task javadocsJar(type: Jar) {
 | 
				
			||||||
    classifier = 'javadoc'
 | 
					    archiveClassifier = 'javadoc'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
publishing {
 | 
					publishing {
 | 
				
			||||||
@@ -57,19 +57,16 @@ publishing {
 | 
				
			|||||||
            
 | 
					            
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
 | 
					            if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
 | 
				
			||||||
                maven {
 | 
					                maven {
 | 
				
			||||||
                    name = "Gitea"
 | 
					                    name = "InmoNexus"
 | 
				
			||||||
                    url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
 | 
					                    url = uri("https://nexus.inmo.dev/repository/maven-releases/")
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
                    credentials(HttpHeaderCredentials) {
 | 
					                    credentials {
 | 
				
			||||||
                        name = "Authorization"
 | 
					                        username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
 | 
				
			||||||
                        value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
 | 
					                        password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
                    authentication {
 | 
					 | 
				
			||||||
                        header(HttpHeaderAuthentication)
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
 | 
					            if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
 | 
				
			||||||
@@ -102,4 +99,27 @@ if (project.hasProperty("signing.gnupg.keyName")) {
 | 
				
			|||||||
            dependsOn(it)
 | 
					            dependsOn(it)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Workaround to make android sign operations depend on signing tasks
 | 
				
			||||||
 | 
					    project.getTasks().withType(AbstractPublishToMaven.class).configureEach {
 | 
				
			||||||
 | 
					        def signingTasks = project.getTasks().withType(Sign.class)
 | 
				
			||||||
 | 
					        mustRunAfter(signingTasks)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Workaround to make test tasks use sign
 | 
				
			||||||
 | 
					    project.getTasks().withType(Sign.class).configureEach { signTask ->
 | 
				
			||||||
 | 
					        def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name)
 | 
				
			||||||
 | 
					        def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign
 | 
				
			||||||
 | 
					        // These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
 | 
				
			||||||
 | 
					        def debugTestTask = tasks.findByName("linkDebugTest$pubName")
 | 
				
			||||||
 | 
					        if (debugTestTask != null) {
 | 
				
			||||||
 | 
					            signTask.mustRunAfter(debugTestTask)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
 | 
				
			||||||
 | 
					        def testTask = tasks.findByName("compileTestKotlin$pubName")
 | 
				
			||||||
 | 
					        if (testTask != null) {
 | 
				
			||||||
 | 
					            signTask.mustRunAfter(testTask)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"Gitea","url":"https://git.inmo.dev/api/packages/InsanusMokrassar/maven","credsType":{"type":"dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository.CredentialsType.HttpHeaderCredentials","headerName":"Authorization","headerValueProperty":"GITEA_TOKEN"}},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}
 | 
					{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}
 | 
				
			||||||
@@ -5,6 +5,7 @@ import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			|||||||
import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
					import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.cache.util.ActualizeAllClearMode
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
@@ -29,7 +30,7 @@ open class ReadCRUDCacheRepo<ObjectType, IdType>(
 | 
				
			|||||||
            kvCache.getAll()
 | 
					            kvCache.getAll()
 | 
				
			||||||
        }.takeIf { it.size.toLong() == count() } ?: parentRepo.getAll().also {
 | 
					        }.takeIf { it.size.toLong() == count() } ?: parentRepo.getAll().also {
 | 
				
			||||||
            locker.withWriteLock {
 | 
					            locker.withWriteLock {
 | 
				
			||||||
                kvCache.actualizeAll(true) { it }
 | 
					                kvCache.actualizeAll(clearMode = ActualizeAllClearMode.BeforeSet) { it }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -148,7 +149,9 @@ open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
    locker,
 | 
					    locker,
 | 
				
			||||||
    idGetter
 | 
					    idGetter
 | 
				
			||||||
),
 | 
					),
 | 
				
			||||||
    CRUDRepo<ObjectType, IdType, InputValueType>
 | 
					    CRUDRepo<ObjectType, IdType, InputValueType> {
 | 
				
			||||||
 | 
					    override suspend fun invalidate() = kvCache.actualizeAll(parentRepo, locker = locker)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
 | 
					fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
 | 
				
			||||||
    kvCache: KVCache<IdType, ObjectType>,
 | 
					    kvCache: KVCache<IdType, ObjectType>,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,11 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache
 | 
					package dev.inmo.micro_utils.repos.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface CacheRepo {
 | 
					interface InvalidatableRepo {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Invalidates its internal data. It __may__ lead to autoreload of data. In case when repo makes autoreload,
 | 
				
			||||||
 | 
					     * it must do loading of data __before__ clear
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    suspend fun invalidate()
 | 
					    suspend fun invalidate()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typealias CacheRepo = InvalidatableRepo
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
					import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
import kotlinx.coroutines.flow.*
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
@@ -48,9 +49,7 @@ open class ReadKeyValueCacheRepo<Key,Value>(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = locker.withWriteLock {
 | 
					    override suspend fun invalidate() = kvCache.actualizeAll(parentRepo, locker = locker)
 | 
				
			||||||
        kvCache.clear()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
 | 
					fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
 | 
				
			||||||
@@ -75,10 +74,6 @@ open class KeyValueCacheRepo<Key,Value>(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = locker.withWriteLock {
 | 
					 | 
				
			||||||
        kvCache.clear()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override suspend fun clear() {
 | 
					    override suspend fun clear() {
 | 
				
			||||||
        parentRepo.clear()
 | 
					        parentRepo.clear()
 | 
				
			||||||
        locker.withWriteLock {
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import dev.inmo.micro_utils.pagination.*
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.utils.*
 | 
					import dev.inmo.micro_utils.pagination.utils.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
					import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
import kotlinx.coroutines.flow.*
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
@@ -47,9 +48,7 @@ open class ReadKeyValuesCacheRepo<Key,Value>(
 | 
				
			|||||||
        kvCache.contains(k)
 | 
					        kvCache.contains(k)
 | 
				
			||||||
    } || parentRepo.contains(k)
 | 
					    } || parentRepo.contains(k)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = locker.withWriteLock {
 | 
					    override suspend fun invalidate() = kvCache.actualizeAll(parentRepo, locker = locker)
 | 
				
			||||||
        kvCache.clear()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
 | 
					fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
 | 
				
			||||||
@@ -84,10 +83,6 @@ open class KeyValuesCacheRepo<Key,Value>(
 | 
				
			|||||||
            kvCache.unset(it)
 | 
					            kvCache.unset(it)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    override suspend fun invalidate() = locker.withWriteLock {
 | 
					 | 
				
			||||||
        kvCache.clear()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
 | 
					fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import dev.inmo.micro_utils.repos.ReadCRUDRepo
 | 
				
			|||||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
					import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
					import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.cache.util.ActualizeAllClearMode
 | 
				
			||||||
import dev.inmo.micro_utils.repos.set
 | 
					import dev.inmo.micro_utils.repos.set
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.delay
 | 
					import kotlinx.coroutines.delay
 | 
				
			||||||
@@ -56,7 +57,7 @@ open class AutoRecacheReadCRUDRepo<RegisteredObject, Id>(
 | 
				
			|||||||
    override suspend fun getAll(): Map<Id, RegisteredObject> = actionWrapper.wrap {
 | 
					    override suspend fun getAll(): Map<Id, RegisteredObject> = actionWrapper.wrap {
 | 
				
			||||||
        originalRepo.getAll()
 | 
					        originalRepo.getAll()
 | 
				
			||||||
    }.onSuccess {
 | 
					    }.onSuccess {
 | 
				
			||||||
        kvCache.actualizeAll(clear = true) { it }
 | 
					        kvCache.actualizeAll(clearMode = ActualizeAllClearMode.BeforeSet) { it }
 | 
				
			||||||
    }.getOrElse {
 | 
					    }.getOrElse {
 | 
				
			||||||
        kvCache.getAll()
 | 
					        kvCache.getAll()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import dev.inmo.micro_utils.repos.ReadKeyValueRepo
 | 
				
			|||||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
					import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
					import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.cache.util.ActualizeAllClearMode
 | 
				
			||||||
import dev.inmo.micro_utils.repos.set
 | 
					import dev.inmo.micro_utils.repos.set
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.delay
 | 
					import kotlinx.coroutines.delay
 | 
				
			||||||
@@ -56,7 +57,7 @@ open class AutoRecacheReadKeyValueRepo<Id, RegisteredObject>(
 | 
				
			|||||||
    override suspend fun getAll(): Map<Id, RegisteredObject> = actionWrapper.wrap {
 | 
					    override suspend fun getAll(): Map<Id, RegisteredObject> = actionWrapper.wrap {
 | 
				
			||||||
        originalRepo.getAll()
 | 
					        originalRepo.getAll()
 | 
				
			||||||
    }.onSuccess {
 | 
					    }.onSuccess {
 | 
				
			||||||
        kvCache.actualizeAll(clear = true) { it }
 | 
					        kvCache.actualizeAll(clearMode = ActualizeAllClearMode.BeforeSet) { it }
 | 
				
			||||||
    }.getOrElse {
 | 
					    }.getOrElse {
 | 
				
			||||||
        kvCache.getAll()
 | 
					        kvCache.getAll()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import dev.inmo.micro_utils.pagination.Pagination
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.*
 | 
					import dev.inmo.micro_utils.repos.cache.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.cache.util.ActualizeAllClearMode
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
@@ -42,7 +43,7 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected open suspend fun actualizeAll() {
 | 
					    protected open suspend fun actualizeAll() {
 | 
				
			||||||
        locker.withWriteLock { kvCache.actualizeAll(parentRepo) }
 | 
					        kvCache.actualizeAll(parentRepo, locker = locker)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = doOrTakeAndActualize(
 | 
					    override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = doOrTakeAndActualize(
 | 
				
			||||||
@@ -72,7 +73,7 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
 | 
				
			|||||||
    override suspend fun getAll(): Map<IdType, ObjectType> = doOrTakeAndActualizeWithWriteLock(
 | 
					    override suspend fun getAll(): Map<IdType, ObjectType> = doOrTakeAndActualizeWithWriteLock(
 | 
				
			||||||
        { getAll().takeIf { it.isNotEmpty() }.optionalOrAbsentIfNull },
 | 
					        { getAll().takeIf { it.isNotEmpty() }.optionalOrAbsentIfNull },
 | 
				
			||||||
        { getAll() },
 | 
					        { getAll() },
 | 
				
			||||||
        { kvCache.actualizeAll(clear = true) { it } }
 | 
					        { kvCache.actualizeAll(clearMode = ActualizeAllClearMode.BeforeSet) { it } }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getById(id: IdType): ObjectType? = doOrTakeAndActualizeWithWriteLock(
 | 
					    override suspend fun getById(id: IdType): ObjectType? = doOrTakeAndActualizeWithWriteLock(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,8 @@ import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.Pagination
 | 
					import dev.inmo.micro_utils.pagination.Pagination
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.cache.util.ActualizeAllClearMode
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import dev.inmo.micro_utils.repos.pagination.getAll
 | 
					 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
import kotlinx.coroutines.flow.*
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
@@ -41,10 +41,7 @@ open class FullReadKeyValueCacheRepo<Key,Value>(
 | 
				
			|||||||
        actualize = { locker.withWriteLock { actualize(it) } }
 | 
					        actualize = { locker.withWriteLock { actualize(it) } }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    protected open suspend fun actualizeAll() {
 | 
					    protected open suspend fun actualizeAll() {
 | 
				
			||||||
        locker.withWriteLock {
 | 
					        kvCache.actualizeAll(parentRepo, locker)
 | 
				
			||||||
            kvCache.clear()
 | 
					 | 
				
			||||||
            kvCache.set(parentRepo.getAll())
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun get(k: Key): Value? = doOrTakeAndActualizeWithWriteLock(
 | 
					    override suspend fun get(k: Key): Value? = doOrTakeAndActualizeWithWriteLock(
 | 
				
			||||||
@@ -74,7 +71,7 @@ open class FullReadKeyValueCacheRepo<Key,Value>(
 | 
				
			|||||||
    override suspend fun getAll(): Map<Key, Value> = doOrTakeAndActualizeWithWriteLock(
 | 
					    override suspend fun getAll(): Map<Key, Value> = doOrTakeAndActualizeWithWriteLock(
 | 
				
			||||||
        { getAll().takeIf { it.isNotEmpty() }.optionalOrAbsentIfNull },
 | 
					        { getAll().takeIf { it.isNotEmpty() }.optionalOrAbsentIfNull },
 | 
				
			||||||
        { getAll() },
 | 
					        { getAll() },
 | 
				
			||||||
        { kvCache.actualizeAll(clear = true) { it } }
 | 
					        { kvCache.actualizeAll(clearMode = ActualizeAllClearMode.BeforeSet) { it } }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = doOrTakeAndActualize(
 | 
					    override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = doOrTakeAndActualize(
 | 
				
			||||||
@@ -150,9 +147,7 @@ open class FullKeyValueCacheRepo<Key,Value>(
 | 
				
			|||||||
    override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
 | 
					    override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() {
 | 
					    override suspend fun invalidate() {
 | 
				
			||||||
        locker.withWriteLock {
 | 
					        kvCache.actualizeAll(parentRepo, locker)
 | 
				
			||||||
            kvCache.actualizeAll(parentRepo)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun clear() {
 | 
					    override suspend fun clear() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.*
 | 
					import dev.inmo.micro_utils.pagination.utils.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.cache.util.ActualizeAllClearMode
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
@@ -41,15 +42,13 @@ open class FullReadKeyValuesCacheRepo<Key,Value>(
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected open suspend fun actualizeKey(k: Key) {
 | 
					    protected open suspend fun actualizeKey(k: Key) {
 | 
				
			||||||
        locker.withWriteLock {
 | 
					        kvCache.actualizeAll(locker = locker, clearMode = ActualizeAllClearMode.Never) {
 | 
				
			||||||
            kvCache.set(k, parentRepo.getAll(k))
 | 
					            mapOf(k to parentRepo.getAll(k))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected open suspend fun actualizeAll() {
 | 
					    protected open suspend fun actualizeAll() {
 | 
				
			||||||
        locker.withWriteLock {
 | 
					        kvCache.actualizeAll(parentRepo, locker = locker)
 | 
				
			||||||
            kvCache.actualizeAll(parentRepo)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
					    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
				
			||||||
@@ -187,9 +186,11 @@ open class FullKeyValuesCacheRepo<Key,Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() {
 | 
					    override suspend fun invalidate() {
 | 
				
			||||||
        locker.withWriteLock {
 | 
					        kvCache.actualizeAll(parentRepo, locker = locker)
 | 
				
			||||||
            kvCache.actualizeAll(parentRepo)
 | 
					    }
 | 
				
			||||||
        }
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun set(toSet: Map<Key, List<Value>>) {
 | 
				
			||||||
 | 
					        super<KeyValuesRepo>.set(toSet)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun removeWithValue(v: Value) {
 | 
					    override suspend fun removeWithValue(v: Value) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,43 +1,169 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.util
 | 
					package dev.inmo.micro_utils.repos.cache.util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					import kotlin.js.JsName
 | 
				
			||||||
 | 
					import kotlin.jvm.JvmName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
					/**
 | 
				
			||||||
    clear: Boolean = true,
 | 
					 * `invalidate`/`actualizeAll` clearing mode. Declare when data in original repo will be cleared
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					sealed interface ActualizeAllClearMode {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instruct user of this mode to clear internal data __before load__ of external data
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    data object BeforeLoad : ActualizeAllClearMode
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instruct user of this mode to clear internal data __after load__ of external data and __before set__ of internal data
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    data object BeforeSet : ActualizeAllClearMode
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instruct user of this mode to never clear internal data
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    data object Never : ActualizeAllClearMode
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithClearBeforeLoad(
 | 
				
			||||||
    getAll: () -> Map<K, V>
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    set(
 | 
					    clear()
 | 
				
			||||||
        getAll().also {
 | 
					    val newData = getAll()
 | 
				
			||||||
            if (clear) {
 | 
					    set(newData)
 | 
				
			||||||
                clear()
 | 
					}
 | 
				
			||||||
            }
 | 
					
 | 
				
			||||||
        }
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithClearBeforeSet(
 | 
				
			||||||
    )
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    val newData = getAll()
 | 
				
			||||||
 | 
					    clear()
 | 
				
			||||||
 | 
					    set(newData)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithoutClear(
 | 
				
			||||||
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    val newData = getAll()
 | 
				
			||||||
 | 
					    set(newData)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@JvmName("actualizeAllWithClearBeforeLoadWithLocker")
 | 
				
			||||||
 | 
					@JsName("actualizeAllWithClearBeforeLoadWithLocker")
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithClearBeforeLoad(
 | 
				
			||||||
 | 
					    locker: SmartRWLocker,
 | 
				
			||||||
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    locker.withWriteLock {
 | 
				
			||||||
 | 
					        clear()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val newData = getAll()
 | 
				
			||||||
 | 
					    locker.withWriteLock {
 | 
				
			||||||
 | 
					        set(newData)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@JvmName("actualizeAllWithClearBeforeSetWithLocker")
 | 
				
			||||||
 | 
					@JsName("actualizeAllWithClearBeforeSetWithLocker")
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithClearBeforeSet(
 | 
				
			||||||
 | 
					    locker: SmartRWLocker,
 | 
				
			||||||
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    val newData = getAll()
 | 
				
			||||||
 | 
					    locker.withWriteLock {
 | 
				
			||||||
 | 
					        clear()
 | 
				
			||||||
 | 
					        set(newData)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@JvmName("actualizeAllWithoutClearWithLocker")
 | 
				
			||||||
 | 
					@JsName("actualizeAllWithoutClearWithLocker")
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithoutClear(
 | 
				
			||||||
 | 
					    locker: SmartRWLocker,
 | 
				
			||||||
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    val newData = getAll()
 | 
				
			||||||
 | 
					    locker.withWriteLock {
 | 
				
			||||||
 | 
					        set(newData)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithClearBeforeLoad(
 | 
				
			||||||
 | 
					    locker: SmartRWLocker? = null,
 | 
				
			||||||
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    locker ?.let {
 | 
				
			||||||
 | 
					        actualizeAllWithClearBeforeLoad(locker = locker, getAll)
 | 
				
			||||||
 | 
					    } ?: actualizeAllWithClearBeforeLoad(getAll)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithClearBeforeSet(
 | 
				
			||||||
 | 
					    locker: SmartRWLocker? = null,
 | 
				
			||||||
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    locker ?.let {
 | 
				
			||||||
 | 
					        actualizeAllWithClearBeforeSet(locker = locker, getAll)
 | 
				
			||||||
 | 
					    } ?: actualizeAllWithClearBeforeSet(getAll)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAllWithoutClear(
 | 
				
			||||||
 | 
					    locker: SmartRWLocker? = null,
 | 
				
			||||||
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    locker ?.let {
 | 
				
			||||||
 | 
					        actualizeAllWithoutClear(locker = locker, getAll)
 | 
				
			||||||
 | 
					    } ?: actualizeAllWithoutClear(getAll)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
				
			||||||
    repo: ReadKeyValueRepo<K, V>,
 | 
					    locker: SmartRWLocker? = null,
 | 
				
			||||||
    clear: Boolean = true,
 | 
					    clearMode: ActualizeAllClearMode = ActualizeAllClearMode.BeforeSet,
 | 
				
			||||||
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    actualizeAll(clear) {
 | 
					    when (clearMode) {
 | 
				
			||||||
        repo.getAll()
 | 
					        ActualizeAllClearMode.BeforeLoad -> locker ?.let {
 | 
				
			||||||
 | 
					            actualizeAllWithClearBeforeLoad(locker = locker, getAll)
 | 
				
			||||||
 | 
					        } ?: actualizeAllWithClearBeforeLoad(getAll)
 | 
				
			||||||
 | 
					        ActualizeAllClearMode.BeforeSet -> locker ?.let {
 | 
				
			||||||
 | 
					            actualizeAllWithClearBeforeSet(locker = locker, getAll)
 | 
				
			||||||
 | 
					        } ?: actualizeAllWithClearBeforeSet(getAll)
 | 
				
			||||||
 | 
					        ActualizeAllClearMode.Never -> locker ?.let {
 | 
				
			||||||
 | 
					            actualizeAllWithoutClear(locker = locker, getAll)
 | 
				
			||||||
 | 
					        } ?: actualizeAllWithoutClear(getAll)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
				
			||||||
 | 
					    parentRepo: ReadKeyValueRepo<K, V>,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker? = null,
 | 
				
			||||||
 | 
					    clearMode: ActualizeAllClearMode = ActualizeAllClearMode.BeforeSet,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    actualizeAll(locker, clearMode) {
 | 
				
			||||||
 | 
					        parentRepo.getAll()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <K, V> KeyValueRepo<K, List<V>>.actualizeAll(
 | 
					suspend inline fun <K, V> KeyValueRepo<K, List<V>>.actualizeAll(
 | 
				
			||||||
    repo: ReadKeyValuesRepo<K, V>,
 | 
					    parentRepo: ReadKeyValuesRepo<K, V>,
 | 
				
			||||||
    clear: Boolean = true,
 | 
					    locker: SmartRWLocker? = null,
 | 
				
			||||||
 | 
					    clearMode: ActualizeAllClearMode = ActualizeAllClearMode.BeforeSet,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    actualizeAll(clear) {
 | 
					    actualizeAll(locker, clearMode) {
 | 
				
			||||||
        repo.getAll()
 | 
					        parentRepo.getAll()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
				
			||||||
    repo: ReadCRUDRepo<V, K>,
 | 
					    parentRepo: ReadCRUDRepo<V, K>,
 | 
				
			||||||
    clear: Boolean = true,
 | 
					    locker: SmartRWLocker? = null,
 | 
				
			||||||
 | 
					    clearMode: ActualizeAllClearMode = ActualizeAllClearMode.BeforeSet,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    actualizeAll(clear) {
 | 
					    actualizeAll(locker, clearMode) {
 | 
				
			||||||
        repo.getAll()
 | 
					        parentRepo.getAll()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos
 | 
					package dev.inmo.micro_utils.repos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.common.diff
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
 | 
					import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
 | 
					import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
 | 
				
			||||||
@@ -130,6 +131,14 @@ interface KeyValuesRepo<Key, Value> : ReadKeyValuesRepo<Key, Value>, WriteKeyVal
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        remove(toRemove)
 | 
					        remove(toRemove)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun set(toSet: Map<Key, List<Value>>) {
 | 
				
			||||||
 | 
					        toSet.forEach { (k, v) ->
 | 
				
			||||||
 | 
					            val diff = getAll(k).diff(v)
 | 
				
			||||||
 | 
					            remove(k, diff.removed.map { it.value })
 | 
				
			||||||
 | 
					            add(k, diff.added.map { it.value })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
typealias OneToManyKeyValueRepo<Key,Value> = KeyValuesRepo<Key, Value>
 | 
					typealias OneToManyKeyValueRepo<Key,Value> = KeyValuesRepo<Key, Value>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,19 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.exposed
 | 
					package dev.inmo.micro_utils.repos.exposed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.repos.CRUDRepo
 | 
					import dev.inmo.micro_utils.repos.CRUDRepo
 | 
				
			||||||
 | 
					import kotlinx.coroutines.channels.BufferOverflow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
					abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    flowsChannelsSize: Int = 0,
 | 
					    flowsChannelsSize: Int = 0,
 | 
				
			||||||
    tableName: String = ""
 | 
					    tableName: String = "",
 | 
				
			||||||
 | 
					    replyCacheInFlows: Int = 0,
 | 
				
			||||||
 | 
					    onBufferOverflowBehaviour: BufferOverflow = BufferOverflow.SUSPEND
 | 
				
			||||||
) :
 | 
					) :
 | 
				
			||||||
    AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
					    AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
        flowsChannelsSize,
 | 
					        flowsChannelsSize,
 | 
				
			||||||
        tableName
 | 
					        tableName,
 | 
				
			||||||
 | 
					        replyCacheInFlows,
 | 
				
			||||||
 | 
					        onBufferOverflowBehaviour
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    ExposedCRUDRepo<ObjectType, IdType>,
 | 
					    ExposedCRUDRepo<ObjectType, IdType>,
 | 
				
			||||||
    CRUDRepo<ObjectType, IdType, InputValueType>
 | 
					    CRUDRepo<ObjectType, IdType, InputValueType>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,14 +35,14 @@ abstract class AbstractExposedReadCRUDRepo<ObjectType, IdType>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    override suspend fun getById(id: IdType): ObjectType? {
 | 
					    override suspend fun getById(id: IdType): ObjectType? {
 | 
				
			||||||
        return transaction(db = database) {
 | 
					        return transaction(db = database) {
 | 
				
			||||||
            select {
 | 
					            selectAll().where {
 | 
				
			||||||
                selectById(id)
 | 
					                selectById(id)
 | 
				
			||||||
            }.limit(1).firstOrNull() ?.asObject
 | 
					            }.limit(1).firstOrNull() ?.asObject
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(id: IdType): Boolean = transaction(db = database) {
 | 
					    override suspend fun contains(id: IdType): Boolean = transaction(db = database) {
 | 
				
			||||||
        select { selectById(id) }.limit(1).any()
 | 
					        selectAll().where { selectById(id) }.limit(1).any()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getAll(): Map<IdType, ObjectType> = transaction(database) {
 | 
					    override suspend fun getAll(): Map<IdType, ObjectType> = transaction(database) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ package dev.inmo.micro_utils.repos.exposed
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.repos.UpdatedValuePair
 | 
					import dev.inmo.micro_utils.repos.UpdatedValuePair
 | 
				
			||||||
import dev.inmo.micro_utils.repos.WriteCRUDRepo
 | 
					import dev.inmo.micro_utils.repos.WriteCRUDRepo
 | 
				
			||||||
 | 
					import kotlinx.coroutines.channels.BufferOverflow
 | 
				
			||||||
import kotlinx.coroutines.flow.*
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
import org.jetbrains.exposed.sql.*
 | 
					import org.jetbrains.exposed.sql.*
 | 
				
			||||||
import org.jetbrains.exposed.sql.statements.*
 | 
					import org.jetbrains.exposed.sql.statements.*
 | 
				
			||||||
@@ -11,19 +12,26 @@ import java.util.Objects
 | 
				
			|||||||
abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
					abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    flowsChannelsSize: Int = 0,
 | 
					    flowsChannelsSize: Int = 0,
 | 
				
			||||||
    tableName: String = "",
 | 
					    tableName: String = "",
 | 
				
			||||||
    replyCacheInFlows: Int = 0
 | 
					    replyCacheInFlows: Int = 0,
 | 
				
			||||||
 | 
					    onBufferOverflowBehaviour: BufferOverflow = BufferOverflow.SUSPEND
 | 
				
			||||||
) :
 | 
					) :
 | 
				
			||||||
    AbstractExposedReadCRUDRepo<ObjectType, IdType>(tableName),
 | 
					    AbstractExposedReadCRUDRepo<ObjectType, IdType>(tableName),
 | 
				
			||||||
    ExposedCRUDRepo<ObjectType, IdType>,
 | 
					    ExposedCRUDRepo<ObjectType, IdType>,
 | 
				
			||||||
    WriteCRUDRepo<ObjectType, IdType, InputValueType>
 | 
					    WriteCRUDRepo<ObjectType, IdType, InputValueType>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    protected val _newObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize)
 | 
					    protected open val _newObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize, onBufferOverflowBehaviour)
 | 
				
			||||||
    protected val _updatedObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize)
 | 
					    protected open val _updatedObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize, onBufferOverflowBehaviour)
 | 
				
			||||||
    protected val _deletedObjectsIdsFlow = MutableSharedFlow<IdType>(replyCacheInFlows, flowsChannelsSize)
 | 
					    protected open val _deletedObjectsIdsFlow = MutableSharedFlow<IdType>(replyCacheInFlows, flowsChannelsSize, onBufferOverflowBehaviour)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow()
 | 
					    override val newObjectsFlow: Flow<ObjectType> by lazy {
 | 
				
			||||||
    override val updatedObjectsFlow: Flow<ObjectType> = _updatedObjectsFlow.asSharedFlow()
 | 
					        _newObjectsFlow.asSharedFlow()
 | 
				
			||||||
    override val deletedObjectsIdsFlow: Flow<IdType> = _deletedObjectsIdsFlow.asSharedFlow()
 | 
					    }
 | 
				
			||||||
 | 
					    override val updatedObjectsFlow: Flow<ObjectType> by lazy {
 | 
				
			||||||
 | 
					        _updatedObjectsFlow.asSharedFlow()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    override val deletedObjectsIdsFlow: Flow<IdType> by lazy {
 | 
				
			||||||
 | 
					        _deletedObjectsIdsFlow.asSharedFlow()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected abstract fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType
 | 
					    protected abstract fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,7 +101,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
        }.let {
 | 
					        }.let {
 | 
				
			||||||
            if (it > 0) {
 | 
					            if (it > 0) {
 | 
				
			||||||
                transaction(db = database) {
 | 
					                transaction(db = database) {
 | 
				
			||||||
                    select {
 | 
					                    selectAll().where {
 | 
				
			||||||
                        selectById(this, id)
 | 
					                        selectById(this, id)
 | 
				
			||||||
                    }.limit(1).firstOrNull() ?.asObject
 | 
					                    }.limit(1).firstOrNull() ?.asObject
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -134,7 +142,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
                ids
 | 
					                ids
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                ids.filter {
 | 
					                ids.filter {
 | 
				
			||||||
                    select { selectById(it) }.limit(1).none()
 | 
					                    selectAll().where { selectById(it) }.limit(1).none()
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }.forEach {
 | 
					        }.forEach {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,7 +65,7 @@ abstract class AbstractExposedKeyValueRepo<Key, Value>(
 | 
				
			|||||||
    override suspend fun unsetWithValues(toUnset: List<Value>) {
 | 
					    override suspend fun unsetWithValues(toUnset: List<Value>) {
 | 
				
			||||||
        transaction(database) {
 | 
					        transaction(database) {
 | 
				
			||||||
            toUnset.flatMap {
 | 
					            toUnset.flatMap {
 | 
				
			||||||
                val keys = select { selectByValue(it) }.mapNotNull { it.asKey }
 | 
					                val keys = selectAll().where { selectByValue(it) }.mapNotNull { it.asKey }
 | 
				
			||||||
                deleteWhere { selectByIds(it, keys) }
 | 
					                deleteWhere { selectByIds(it, keys) }
 | 
				
			||||||
                keys
 | 
					                keys
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,11 +24,11 @@ abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
 | 
				
			|||||||
    abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
 | 
					    abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun get(k: Key): Value? = transaction(database) {
 | 
					    override suspend fun get(k: Key): Value? = transaction(database) {
 | 
				
			||||||
        select { selectById(k) }.limit(1).firstOrNull() ?.asObject
 | 
					        selectAll().where { selectById(k) }.limit(1).firstOrNull() ?.asObject
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(key: Key): Boolean = transaction(database) {
 | 
					    override suspend fun contains(key: Key): Boolean = transaction(database) {
 | 
				
			||||||
        select { selectById(key) }.limit(1).any()
 | 
					        selectAll().where { selectById(key) }.limit(1).any()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getAll(): Map<Key, Value> = transaction(database) { selectAll().associate { it.asKey to it.asObject } }
 | 
					    override suspend fun getAll(): Map<Key, Value> = transaction(database) { selectAll().associate { it.asKey to it.asObject } }
 | 
				
			||||||
@@ -46,7 +46,7 @@ abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = transaction(database) {
 | 
					    override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = transaction(database) {
 | 
				
			||||||
        select { selectByValue(v) }.selectPaginated(
 | 
					        selectAll().where { selectByValue(v) }.selectPaginated(
 | 
				
			||||||
            pagination,
 | 
					            pagination,
 | 
				
			||||||
            keyColumn,
 | 
					            keyColumn,
 | 
				
			||||||
            reversed
 | 
					            reversed
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,7 +65,7 @@ open class ExposedKeyValueRepo<Key, Value>(
 | 
				
			|||||||
    override suspend fun unsetWithValues(toUnset: List<Value>) {
 | 
					    override suspend fun unsetWithValues(toUnset: List<Value>) {
 | 
				
			||||||
        transaction(database) {
 | 
					        transaction(database) {
 | 
				
			||||||
            toUnset.flatMap {
 | 
					            toUnset.flatMap {
 | 
				
			||||||
                val keys = select { valueColumn.eq(it) }.mapNotNull { it[keyColumn] }
 | 
					                val keys = selectAll().where { valueColumn.eq(it) }.mapNotNull { it[keyColumn] }
 | 
				
			||||||
                deleteWhere { keyColumn.inList(keys) }
 | 
					                deleteWhere { keyColumn.inList(keys) }
 | 
				
			||||||
                keys
 | 
					                keys
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@ abstract class AbstractExposedKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
        transaction(database) {
 | 
					        transaction(database) {
 | 
				
			||||||
            toAdd.keys.flatMap { k ->
 | 
					            toAdd.keys.flatMap { k ->
 | 
				
			||||||
                toAdd[k] ?.mapNotNull { v ->
 | 
					                toAdd[k] ?.mapNotNull { v ->
 | 
				
			||||||
                    if (select { selectById(k).and(selectByValue(v)) }.limit(1).any()) {
 | 
					                    if (selectAll().where { selectById(k).and(selectByValue(v)) }.limit(1).any()) {
 | 
				
			||||||
                        return@mapNotNull null
 | 
					                        return@mapNotNull null
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    val insertResult = insert {
 | 
					                    val insertResult = insert {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,7 @@ abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
        get() = asKey
 | 
					        get() = asKey
 | 
				
			||||||
    abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
 | 
					    abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(k: Key): Long = transaction(database) { select { selectById(k) }.count() }
 | 
					    override suspend fun count(k: Key): Long = transaction(database) { selectAll().where { selectById(k) }.count() }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(): Long = transaction(database) { selectAll().count() }
 | 
					    override suspend fun count(): Long = transaction(database) { selectAll().count() }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,7 +28,7 @@ abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
        pagination: Pagination,
 | 
					        pagination: Pagination,
 | 
				
			||||||
        reversed: Boolean
 | 
					        reversed: Boolean
 | 
				
			||||||
    ): PaginationResult<Value> = transaction(database) {
 | 
					    ): PaginationResult<Value> = transaction(database) {
 | 
				
			||||||
        select { selectById(k) }.selectPaginated(
 | 
					        selectAll().where { selectById(k) }.selectPaginated(
 | 
				
			||||||
            pagination,
 | 
					            pagination,
 | 
				
			||||||
            keyColumn,
 | 
					            keyColumn,
 | 
				
			||||||
            reversed
 | 
					            reversed
 | 
				
			||||||
@@ -55,7 +55,7 @@ abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
        pagination: Pagination,
 | 
					        pagination: Pagination,
 | 
				
			||||||
        reversed: Boolean
 | 
					        reversed: Boolean
 | 
				
			||||||
    ): PaginationResult<Key> = transaction(database) {
 | 
					    ): PaginationResult<Key> = transaction(database) {
 | 
				
			||||||
        select { selectByValue(v) }.selectPaginated(
 | 
					        selectAll().where { selectByValue(v) }.selectPaginated(
 | 
				
			||||||
            pagination,
 | 
					            pagination,
 | 
				
			||||||
            keyColumn,
 | 
					            keyColumn,
 | 
				
			||||||
            reversed
 | 
					            reversed
 | 
				
			||||||
@@ -65,11 +65,11 @@ abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(k: Key): Boolean = transaction(database) {
 | 
					    override suspend fun contains(k: Key): Boolean = transaction(database) {
 | 
				
			||||||
        select { selectById(k) }.limit(1).any()
 | 
					        selectAll().where { selectById(k) }.limit(1).any()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(k: Key, v: Value): Boolean = transaction(database) {
 | 
					    override suspend fun contains(k: Key, v: Value): Boolean = transaction(database) {
 | 
				
			||||||
        select { selectById(k).and(selectByValue(v)) }.limit(1).any()
 | 
					        selectAll().where { selectById(k).and(selectByValue(v)) }.limit(1).any()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getAll(reverseLists: Boolean): Map<Key, List<Value>> = transaction(database) {
 | 
					    override suspend fun getAll(reverseLists: Boolean): Map<Key, List<Value>> = transaction(database) {
 | 
				
			||||||
@@ -85,9 +85,9 @@ abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    override suspend fun getAll(k: Key, reverseLists: Boolean): List<Value> = transaction(database) {
 | 
					    override suspend fun getAll(k: Key, reverseLists: Boolean): List<Value> = transaction(database) {
 | 
				
			||||||
        val query = if (reverseLists) {
 | 
					        val query = if (reverseLists) {
 | 
				
			||||||
            select { selectById(k) }.orderBy(keyColumn, SortOrder.DESC)
 | 
					            selectAll().where { selectById(k) }.orderBy(keyColumn, SortOrder.DESC)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            select { selectById(k) }
 | 
					            selectAll().where { selectById(k) }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        query.map {
 | 
					        query.map {
 | 
				
			||||||
            it.asObject
 | 
					            it.asObject
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ open class ExposedKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
        transaction(database) {
 | 
					        transaction(database) {
 | 
				
			||||||
            toAdd.keys.flatMap { k ->
 | 
					            toAdd.keys.flatMap { k ->
 | 
				
			||||||
                toAdd[k] ?.mapNotNull { v ->
 | 
					                toAdd[k] ?.mapNotNull { v ->
 | 
				
			||||||
                    if (select { keyColumn.eq(k).and(valueColumn.eq(v)) }.limit(1).count() > 0) {
 | 
					                    if (selectAll().where { keyColumn.eq(k).and(valueColumn.eq(v)) }.limit(1).count() > 0) {
 | 
				
			||||||
                        return@mapNotNull null
 | 
					                        return@mapNotNull null
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    val insertResult = insert {
 | 
					                    val insertResult = insert {
 | 
				
			||||||
@@ -69,7 +69,7 @@ open class ExposedKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    override suspend fun removeWithValue(v: Value) {
 | 
					    override suspend fun removeWithValue(v: Value) {
 | 
				
			||||||
        transaction(database) {
 | 
					        transaction(database) {
 | 
				
			||||||
            val keys = select { selectByValue(v) }.map { it.asKey }
 | 
					            val keys = selectAll().where { selectByValue(v) }.map { it.asKey }
 | 
				
			||||||
            deleteWhere { SqlExpressionBuilder.selectByValue(v) }
 | 
					            deleteWhere { SqlExpressionBuilder.selectByValue(v) }
 | 
				
			||||||
            keys
 | 
					            keys
 | 
				
			||||||
        }.forEach {
 | 
					        }.forEach {
 | 
				
			||||||
@@ -85,7 +85,7 @@ open class ExposedKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    override suspend fun clearWithValue(v: Value) {
 | 
					    override suspend fun clearWithValue(v: Value) {
 | 
				
			||||||
        transaction(database) {
 | 
					        transaction(database) {
 | 
				
			||||||
            val toClear = select { selectByValue(v) }
 | 
					            val toClear = selectAll().where { selectByValue(v) }
 | 
				
			||||||
                .asSequence()
 | 
					                .asSequence()
 | 
				
			||||||
                .map { it.asKey to it.asObject }
 | 
					                .map { it.asKey to it.asObject }
 | 
				
			||||||
                .groupBy { it.first }
 | 
					                .groupBy { it.first }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ class ExposedStandardVersionsRepoProxy(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getTableVersion(tableName: String): Int? = transaction(database) {
 | 
					    override suspend fun getTableVersion(tableName: String): Int? = transaction(database) {
 | 
				
			||||||
        select { tableNameColumn.eq(tableName) }.limit(1).firstOrNull() ?.getOrNull(tableVersionColumn)
 | 
					        selectAll().where { tableNameColumn.eq(tableName) }.limit(1).firstOrNull() ?.getOrNull(tableVersionColumn)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun updateTableVersion(tableName: String, version: Int) {
 | 
					    override suspend fun updateTableVersion(tableName: String, version: Int) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,6 @@ dependencies {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								resources/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								resources/build.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.multiplatform"
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.plugin.serialization"
 | 
				
			||||||
 | 
					    id "com.android.library"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64ProjectPresetPath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					kotlin {
 | 
				
			||||||
 | 
					    sourceSets {
 | 
				
			||||||
 | 
					        commonMain {
 | 
				
			||||||
 | 
					            dependencies {
 | 
				
			||||||
 | 
					                api project(":micro_utils.language_codes")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        androidMain {
 | 
				
			||||||
 | 
					            dependsOn(jvmMain)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.content.res.Configuration
 | 
				
			||||||
 | 
					import android.content.res.Resources
 | 
				
			||||||
 | 
					import android.os.Build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun StringResource.translation(configuration: Configuration): String = translation(
 | 
				
			||||||
 | 
					    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
 | 
				
			||||||
 | 
					        configuration.locales[0]
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        configuration.locale
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					fun StringResource.translation(resources: Resources): String = translation(resources.configuration)
 | 
				
			||||||
 | 
					fun StringResource.translation(context: Context): String = translation(context.resources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Configuration.translation(resource: StringResource): String = resource.translation(this)
 | 
				
			||||||
 | 
					fun Resources.translation(resource: StringResource): String = configuration.translation(resource)
 | 
				
			||||||
 | 
					fun Context.translation(resource: StringResource): String = resources.translation(resource)
 | 
				
			||||||
							
								
								
									
										103
									
								
								resources/src/commonMain/kotlin/StringResource.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								resources/src/commonMain/kotlin/StringResource.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.language_codes.IetfLang
 | 
				
			||||||
 | 
					import kotlinx.serialization.KSerializer
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					import kotlinx.serialization.descriptors.SerialDescriptor
 | 
				
			||||||
 | 
					import kotlinx.serialization.encoding.Decoder
 | 
				
			||||||
 | 
					import kotlinx.serialization.encoding.Encoder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Use this class as a type of your strings object fields. For example:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ```kotlin
 | 
				
			||||||
 | 
					 * object Strings {
 | 
				
			||||||
 | 
					 *     val someResource: StringResource
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * ```
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use [buildStringResource] for useful creation of string resource
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see buildStringResource
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Serializable(StringResource.Companion::class)
 | 
				
			||||||
 | 
					data class StringResource(
 | 
				
			||||||
 | 
					    val default: String,
 | 
				
			||||||
 | 
					    val translations: Map<IetfLang, Lazy<String>>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    class Builder(
 | 
				
			||||||
 | 
					        var default: String
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        private val map = mutableMapOf<IetfLang, Lazy<String>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        infix fun IetfLang.variant(value: Lazy<String>) {
 | 
				
			||||||
 | 
					            map[this] = value
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        infix fun IetfLang.variant(value: () -> String) = this variant lazy(value)
 | 
				
			||||||
 | 
					        infix fun IetfLang.variant(value: String) = this variant lazyOf(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        operator fun IetfLang.invoke(value: () -> String) = this variant value
 | 
				
			||||||
 | 
					        operator fun IetfLang.invoke(value: String) = this variant value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        infix fun String.variant(value: Lazy<String>) = IetfLang(this) variant value
 | 
				
			||||||
 | 
					        infix fun String.variant(value: () -> String) = IetfLang(this) variant lazy(value)
 | 
				
			||||||
 | 
					        infix fun String.variant(value: String) = this variant lazyOf(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        operator fun String.invoke(value: () -> String) = this variant value
 | 
				
			||||||
 | 
					        operator fun String.invoke(value: String) = this variant value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun build() = StringResource(default, map.toMap())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun translation(languageCode: IetfLang?): String {
 | 
				
			||||||
 | 
					        if (languageCode == null) {
 | 
				
			||||||
 | 
					            return default
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        translations[languageCode] ?.let { return it.value }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return languageCode.parentLang ?.let {
 | 
				
			||||||
 | 
					            translations[it] ?.value
 | 
				
			||||||
 | 
					        } ?: default
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object : KSerializer<StringResource> {
 | 
				
			||||||
 | 
					        @Serializable
 | 
				
			||||||
 | 
					        private class Surrogate(
 | 
				
			||||||
 | 
					            val default: String,
 | 
				
			||||||
 | 
					            val translations: Map<String, String>
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        override val descriptor: SerialDescriptor
 | 
				
			||||||
 | 
					            get() = Surrogate.serializer().descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        override fun deserialize(decoder: Decoder): StringResource {
 | 
				
			||||||
 | 
					            val surrogate = Surrogate.serializer().deserialize(decoder)
 | 
				
			||||||
 | 
					            return StringResource(
 | 
				
			||||||
 | 
					                surrogate.default,
 | 
				
			||||||
 | 
					                surrogate.translations.map { IetfLang(it.key) to lazyOf(it.value) }.toMap()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        override fun serialize(encoder: Encoder, value: StringResource) {
 | 
				
			||||||
 | 
					            Surrogate.serializer().serialize(
 | 
				
			||||||
 | 
					                encoder,
 | 
				
			||||||
 | 
					                Surrogate(
 | 
				
			||||||
 | 
					                    value.default,
 | 
				
			||||||
 | 
					                    value.translations.map {
 | 
				
			||||||
 | 
					                        it.key.code to it.value.value
 | 
				
			||||||
 | 
					                    }.toMap()
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun buildStringResource(
 | 
				
			||||||
 | 
					    default: String,
 | 
				
			||||||
 | 
					    builder: StringResource.Builder.() -> Unit = {}
 | 
				
			||||||
 | 
					): StringResource {
 | 
				
			||||||
 | 
					    return StringResource.Builder(default).apply(builder).build()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								resources/src/jsMain/kotlin/StringResourceExtensions.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								resources/src/jsMain/kotlin/StringResourceExtensions.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.language_codes.IetfLang
 | 
				
			||||||
 | 
					import kotlinx.browser.window
 | 
				
			||||||
 | 
					import org.w3c.dom.NavigatorLanguage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun StringResource.translation(language: NavigatorLanguage) = translation(
 | 
				
			||||||
 | 
					    language.language.unsafeCast<String?>() ?.let { IetfLang(it) }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun StringResource.translation() = translation(window.navigator)
 | 
				
			||||||
							
								
								
									
										10
									
								
								resources/src/jvmMain/kotlin/StringResourceLocaleGetter.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								resources/src/jvmMain/kotlin/StringResourceLocaleGetter.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.language_codes.toIetfLang
 | 
				
			||||||
 | 
					import java.util.Locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun StringResource.translation(locale: Locale = Locale.getDefault()): String {
 | 
				
			||||||
 | 
					    return translation(locale.toIetfLang())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Locale.translation(resource: StringResource): String = resource.translation(this)
 | 
				
			||||||
@@ -16,11 +16,16 @@ import kotlinx.serialization.encoding.Encoder
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
open class MapperDeserializationStrategy<I, O>(
 | 
					open class MapperDeserializationStrategy<I, O>(
 | 
				
			||||||
    private val base: DeserializationStrategy<I>,
 | 
					    private val base: DeserializationStrategy<I>,
 | 
				
			||||||
    private val deserialize: (I) -> O
 | 
					    private val deserialize: (Decoder, I) -> O
 | 
				
			||||||
) : DeserializationStrategy<O> {
 | 
					) : DeserializationStrategy<O> {
 | 
				
			||||||
    override val descriptor: SerialDescriptor = base.descriptor
 | 
					    override val descriptor: SerialDescriptor = base.descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(
 | 
				
			||||||
 | 
					        base: DeserializationStrategy<I>,
 | 
				
			||||||
 | 
					        deserialize: (I) -> O
 | 
				
			||||||
 | 
					    ) : this(base, { _, i -> deserialize(i) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun deserialize(decoder: Decoder): O {
 | 
					    override fun deserialize(decoder: Decoder): O {
 | 
				
			||||||
        return deserialize(base.deserialize(decoder))
 | 
					        return deserialize(decoder, base.deserialize(decoder))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.serialization.mapper
 | 
					package dev.inmo.micro_utils.serialization.mapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import kotlinx.serialization.KSerializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.SerializationStrategy
 | 
					import kotlinx.serialization.SerializationStrategy
 | 
				
			||||||
import kotlinx.serialization.descriptors.SerialDescriptor
 | 
					import kotlinx.serialization.descriptors.SerialDescriptor
 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					 | 
				
			||||||
import kotlinx.serialization.encoding.Encoder
 | 
					import kotlinx.serialization.encoding.Encoder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -11,15 +9,20 @@ import kotlinx.serialization.encoding.Encoder
 | 
				
			|||||||
 * serialization
 | 
					 * serialization
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param base Serializer for [I]
 | 
					 * @param base Serializer for [I]
 | 
				
			||||||
 * @param serialize Will be used in [serialize] method to convert incoming [O] to [I] and serialize with [base]
 | 
					 * @param internalSerialize Will be used in [internalSerialize] method to convert incoming [O] to [I] and serialize with [base]
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
open class MapperSerializationStrategy<I, O>(
 | 
					open class MapperSerializationStrategy<I, O>(
 | 
				
			||||||
    private val base: SerializationStrategy<I>,
 | 
					    private val base: SerializationStrategy<I>,
 | 
				
			||||||
    private val serialize: (O) -> I
 | 
					    private val internalSerialize: (Encoder, O) -> I
 | 
				
			||||||
) : SerializationStrategy<O> {
 | 
					) : SerializationStrategy<O> {
 | 
				
			||||||
    override val descriptor: SerialDescriptor = base.descriptor
 | 
					    override val descriptor: SerialDescriptor = base.descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(
 | 
				
			||||||
 | 
					        base: SerializationStrategy<I>,
 | 
				
			||||||
 | 
					        serialize: (O) -> I
 | 
				
			||||||
 | 
					    ) : this(base, { _, o -> serialize(o) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun serialize(encoder: Encoder, value: O) {
 | 
					    override fun serialize(encoder: Encoder, value: O) {
 | 
				
			||||||
        base.serialize(encoder, serialize(value))
 | 
					        base.serialize(encoder, internalSerialize(encoder, value))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.serialization.mapper
 | 
					package dev.inmo.micro_utils.serialization.mapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.DeserializationStrategy
 | 
				
			||||||
import kotlinx.serialization.KSerializer
 | 
					import kotlinx.serialization.KSerializer
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerializationStrategy
 | 
				
			||||||
import kotlinx.serialization.descriptors.SerialDescriptor
 | 
					import kotlinx.serialization.descriptors.SerialDescriptor
 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					import kotlinx.serialization.encoding.Decoder
 | 
				
			||||||
import kotlinx.serialization.encoding.Encoder
 | 
					import kotlinx.serialization.encoding.Encoder
 | 
				
			||||||
@@ -15,16 +17,28 @@ import kotlinx.serialization.encoding.Encoder
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
open class MapperSerializer<I, O>(
 | 
					open class MapperSerializer<I, O>(
 | 
				
			||||||
    private val base: KSerializer<I>,
 | 
					    private val base: KSerializer<I>,
 | 
				
			||||||
    private val serialize: (O) -> I,
 | 
					    private val serialize: (Encoder, O) -> I,
 | 
				
			||||||
    private val deserialize: (I) -> O
 | 
					    private val deserialize: (Decoder, I) -> O
 | 
				
			||||||
) : KSerializer<O> {
 | 
					) : KSerializer<O>,
 | 
				
			||||||
 | 
					    DeserializationStrategy<O> by MapperDeserializationStrategy<I, O>(base, deserialize),
 | 
				
			||||||
 | 
					    SerializationStrategy<O> by MapperSerializationStrategy<I, O>(base, serialize) {
 | 
				
			||||||
    override val descriptor: SerialDescriptor = base.descriptor
 | 
					    override val descriptor: SerialDescriptor = base.descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun deserialize(decoder: Decoder): O {
 | 
					    constructor(
 | 
				
			||||||
        return deserialize(base.deserialize(decoder))
 | 
					        base: KSerializer<I>,
 | 
				
			||||||
    }
 | 
					        serialize: (O) -> I,
 | 
				
			||||||
 | 
					        deserialize: (I) -> O
 | 
				
			||||||
 | 
					    ) : this(base, { _, o -> serialize(o) }, { _, i -> deserialize(i) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun serialize(encoder: Encoder, value: O) {
 | 
					    constructor(
 | 
				
			||||||
        base.serialize(encoder, serialize(value))
 | 
					        base: KSerializer<I>,
 | 
				
			||||||
    }
 | 
					        serialize: (Encoder, O) -> I,
 | 
				
			||||||
 | 
					        deserialize: (I) -> O
 | 
				
			||||||
 | 
					    ) : this(base, serialize, { _, i -> deserialize(i) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(
 | 
				
			||||||
 | 
					        base: KSerializer<I>,
 | 
				
			||||||
 | 
					        serialize: (O) -> I,
 | 
				
			||||||
 | 
					        deserialize: (Decoder, I) -> O
 | 
				
			||||||
 | 
					    ) : this(base, { _, o -> serialize(o) }, deserialize)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,9 @@ String[] includes = [
 | 
				
			|||||||
    ":serialization:mapper",
 | 
					    ":serialization:mapper",
 | 
				
			||||||
    ":startup:plugin",
 | 
					    ":startup:plugin",
 | 
				
			||||||
    ":startup:launcher",
 | 
					    ":startup:launcher",
 | 
				
			||||||
 | 
					    ":colors:common",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ":resources",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ":fsm:common",
 | 
					    ":fsm:common",
 | 
				
			||||||
    ":fsm:repos:common",
 | 
					    ":fsm:repos:common",
 | 
				
			||||||
@@ -59,5 +62,3 @@ includes.each { originalName ->
 | 
				
			|||||||
    project.name = projectName
 | 
					    project.name = projectName
 | 
				
			||||||
    project.projectDir = new File(projectDirectory)
 | 
					    project.projectDir = new File(projectDirectory)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
enableFeaturePreview("VERSION_CATALOGS")
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,8 +28,8 @@ application {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    sourceCompatibility = JavaVersion.VERSION_1_8
 | 
					    sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    targetCompatibility = JavaVersion.VERSION_1_8
 | 
					    targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user