Skip to content

Commit

Permalink
Release 10.0.0
Browse files Browse the repository at this point in the history
Release 10.0.0
  • Loading branch information
robot-divkit committed Oct 11, 2022
1 parent 6ca6ce2 commit 0242075
Show file tree
Hide file tree
Showing 8 changed files with 466 additions and 76 deletions.
15 changes: 4 additions & 11 deletions Core/BaseTiny/Atomic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,20 @@ import Foundation

public final class Atomic<T> {
private var unsafeValue: T
private let queue: DispatchQueue
private let lock = RWLock()

public init(initialValue: T, accessQueue: DispatchQueue) {
public init(initialValue: T) {
unsafeValue = initialValue
queue = accessQueue
}

@inlinable
public convenience init(initialValue: T, label: String) {
let accessQueue = DispatchQueue(label: label, attributes: [.concurrent])
self.init(initialValue: initialValue, accessQueue: accessQueue)
}

public func accessRead<U>(_ block: (T) throws -> U) rethrows -> U {
try queue.sync {
try lock.read {
try block(unsafeValue)
}
}

public func accessWrite<U>(_ block: (inout T) throws -> U) rethrows -> U {
try queue.sync(flags: .barrier) {
try lock.write {
try block(&unsafeValue)
}
}
Expand Down
15 changes: 7 additions & 8 deletions Core/BaseTiny/Memoization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import Foundation

private let accessQueue = DispatchQueue(label: "Memoization queue", attributes: [.concurrent])
private let assignmentQueue = DispatchQueue(
label: "Memoization optimization assignment (for classes)",
attributes: [.concurrent]
Expand All @@ -22,14 +21,14 @@ private func cachedValue<A, B>(
}

public func memoize<A: Hashable, B>(_ f: @escaping (A) throws -> B) -> (A) throws -> B {
let cache = Atomic(initialValue: [A: B](), accessQueue: accessQueue)
let cache = Atomic(initialValue: [A: B]())
return { (input: A) -> B in
try cachedValue(from: cache, for: input, fallback: f)
}
}

public func memoize<A: Hashable, B>(_ f: @escaping (A) -> B) -> (A) -> B {
let cache = Atomic(initialValue: [A: B](), accessQueue: accessQueue)
let cache = Atomic(initialValue: [A: B]())
return { (input: A) -> B in
cachedValue(from: cache, for: input, fallback: f)
}
Expand All @@ -41,7 +40,7 @@ private struct MemoizeParams2<A: Hashable, B: Hashable>: Hashable {
}

public func memoize<A: Hashable, B: Hashable, C>(_ f: @escaping (A, B) -> C) -> (A, B) -> C {
let cache = Atomic(initialValue: [MemoizeParams2<A, B>: C](), accessQueue: accessQueue)
let cache = Atomic(initialValue: [MemoizeParams2<A, B>: C]())
return { (a: A, b: B) -> C in
cachedValue(from: cache, for: MemoizeParams2(a: a, b: b), fallback: { f($0.a, $0.b) })
}
Expand Down Expand Up @@ -73,9 +72,9 @@ private class MemoizeParams3AClass<A: Hashable, B: Hashable, C: Hashable>: Hasha

static func ==(lhs: MemoizeParams3AClass, rhs: MemoizeParams3AClass) -> Bool {
// This 🦃 performs a very specific optimization for the case when
// we put the calculcations for the specific string (which has reference type) to the cache,
// we put the calculations for the specific string (which has reference type) to the cache,
// but _sometimes_ we re-create the instance of this string. Thus, if we don't modify
// dictionary key, we'll always miss comparation by reference.
// dictionary key, we'll always miss comparison by reference.
// Here we rely on the implementation detail of Dictionary, namely we hope that
// `lhs` corresponds to the key _already contained_ in dictionary and `rhs` corresponds
// to the key by which we're trying to get the value.
Expand All @@ -96,7 +95,7 @@ public func memoize<
C: Hashable,
D
>(_ f: @escaping (A, B, C) -> D) -> (A, B, C) -> D {
let cache = Atomic(initialValue: [MemoizeParams3<A, B, C>: D](), accessQueue: accessQueue)
let cache = Atomic(initialValue: [MemoizeParams3<A, B, C>: D]())
return { (a: A, b: B, c: C) -> D in
cachedValue(
from: cache,
Expand All @@ -112,7 +111,7 @@ public func memoizeAClass<
C: Hashable,
D
>(_ f: @escaping (A, B, C) -> D) -> (A, B, C) -> D where A: AnyObject {
let cache = Atomic(initialValue: [MemoizeParams3AClass<A, B, C>: D](), accessQueue: accessQueue)
let cache = Atomic(initialValue: [MemoizeParams3AClass<A, B, C>: D]())
return { (a: A, b: B, c: C) -> D in
cachedValue(
from: cache,
Expand Down
8 changes: 4 additions & 4 deletions Core/Base/RWLock.swift → Core/BaseTiny/RWLock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ public final class RWLock {
pthread_rwlock_destroy(&lock)
}

public func read<T>(_ block: () -> T) -> T {
public func read<T>(_ block: () throws -> T) rethrows -> T {
pthread_rwlock_rdlock(&lock)
defer { pthread_rwlock_unlock(&lock) }
return block()
return try block()
}

public func write<T>(_ block: () -> T) -> T {
public func write<T>(_ block: () throws -> T) rethrows -> T {
pthread_rwlock_wrlock(&lock)
defer { pthread_rwlock_unlock(&lock) }
return block()
return try block()
}
}
1 change: 0 additions & 1 deletion Core/CommonCore/Theme.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright 2021 Yandex LLC. All rights reserved.

import BaseTiny
import BaseUI

public enum Theme: String {
Expand Down
2 changes: 1 addition & 1 deletion DivKit/DivKitInfo.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
public enum DivKitInfo {
public static let version = "9.0.0"
public static let version = "10.0.0"
}
12 changes: 9 additions & 3 deletions DivKit/Extensions/ArrayExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ extension Array where Element == Div {
mappedBy modificator: (Div, Block) throws -> T
) throws -> [T] {
try iterativeFlatMap { div, index in
let divContext = modified(context) { $0.parentPath += index }
let block = try? div.value.makeBlock(context: divContext)
return try block.map { try modificator(div, $0) }
let itemContext = modified(context) { $0.parentPath += index }
let block: Block
do {
block = try div.value.makeBlock(context: itemContext)
} catch {
DivKitLogger.error("Failed to create block: \(error)")
return nil
}
return try modificator(div, block)
}
}

Expand Down
83 changes: 35 additions & 48 deletions DivKitExtensions/Lottie/LottieExtensionHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@ public final class LottieExtensionHandler: DivExtensionHandler {
div: DivBase,
context: DivBlockModelingContext
) -> Block {
let extensionParams = div.extensions?
.first(where: { $0.id == self.id })
guard let extensionParams = extensionParams?.params,
let lottieValue = LottieValues(
params: extensionParams
) else { return block }
let extensionData = div.extensions?.first { $0.id == id }
guard let paramsDict = extensionData?.params,
let params = LottieExtensionParams(params: paramsDict) else {
return block
}

let animationHolder: AnimationHolder
switch lottieValue.source {
switch params.source {
case let .url(url):
animationHolder = RemoteAnimationHolder(
url: url,
Expand All @@ -49,8 +48,8 @@ public final class LottieExtensionHandler: DivExtensionHandler {
animatableView: Lazy(
getter: {
self.factory.createAnimatableView(
withMode: lottieValue.repeatMode.repeateMode,
repeatCount: lottieValue.repeatCount
withMode: params.repeatMode,
repeatCount: params.repeatCount
)
}
),
Expand All @@ -61,25 +60,16 @@ public final class LottieExtensionHandler: DivExtensionHandler {
}
}

extension LottieValues.RepeatMode {
var repeateMode: AnimationRepeatMode {
switch self {
case .reverse:
return .reverse
case .restart:
return .restart
}
}
}

private class JSONAnimationHolder: AnimationHolder {
let animation: AnimationSourceType?

init(json: [String: Any]) {
self.animation = .json(json)
}

func requestAnimationWithCompletion(_ completion: @escaping (AnimationSourceType?) -> Void) -> Cancellable? {
func requestAnimationWithCompletion(
_ completion: @escaping (AnimationSourceType?) -> Void
) -> Cancellable? {
completion(animation)
return nil
}
Expand All @@ -97,53 +87,50 @@ private class JSONAnimationHolder: AnimationHolder {
}
}

private struct LottieValues {
enum ValuesError: String, Error {
case notValidJSONOrURL
case notValidRepeatCount
case notValidRepeatMode
}

private struct LottieExtensionParams {
enum Source {
case json([String: Any])
case url(URL)
}

enum RepeatMode: String {
case reverse
case restart
}

var source: Source
var repeatCount: Float
var repeatMode: RepeatMode
var repeatMode: AnimationRepeatMode

init?(params: [String: Any]) {
if let json = params["lottie_json"] as? [String: Any] {
source = .json(json)
} else if let urlString = params["lottie_url"] as? String, let url = URL(string: urlString) {
} else if let urlString = params["lottie_url"] as? String,
let url = URL(string: urlString) {
source = .url(url)
} else {
DivKitLogger.error("Not valid lottie_json or lottie_url")
return nil
}

if let repeatCount = params["repeat_count"] as? Float {
self.repeatCount = repeatCount
if let repeatCount = params["repeat_count"] {
if let repeatCountFloat = repeatCount as? Float {
self.repeatCount = repeatCountFloat
} else {
DivKitLogger.error("Not valid repeat_count")
return nil
}
} else {
DivKitLogger.error("Not valid repeat_count")
return nil
self.repeatCount = 0
}

let repeatModeString = params["repeat_mode"] as? String
switch repeatModeString {
case "reverse":
self.repeatMode = .reverse
case "restart":

if let repeatMode = params["repeat_mode"] {
switch repeatMode as? String {
case "reverse":
self.repeatMode = .reverse
case "restart":
self.repeatMode = .restart
default:
DivKitLogger.error("Not valid repeat_mode")
return nil
}
} else {
self.repeatMode = .restart
default:
DivKitLogger.error("Not valid repeat_mode")
return nil
}
}
}
Loading

0 comments on commit 0242075

Please sign in to comment.