#if os(macOS)
import SystemConfiguration
#endif
// This file was autogenerated by some hot garbage in the `uniffi` crate.
// Trust me, you don't want to mess with it!

// swiftlint:disable all
import Foundation

// Depending on the consumer's build setup, the low-level FFI code
// might be in a separate module, or it might be compiled inline into
// this module. This is a bit of light hackery to work with both.
#if canImport(CooklangParserFFI)
    import CooklangParserFFI
#endif

private extension RustBuffer {
    // Allocate a new buffer, copying the contents of a `UInt8` array.
    init(bytes: [UInt8]) {
        let rbuf = bytes.withUnsafeBufferPointer { ptr in
            RustBuffer.from(ptr)
        }
        self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data)
    }

    static func empty() -> RustBuffer {
        RustBuffer(capacity: 0, len: 0, data: nil)
    }

    static func from(_ ptr: UnsafeBufferPointer<UInt8>) -> RustBuffer {
        try! rustCall { ffi_cooklang_bindings_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) }
    }

    // Frees the buffer in place.
    // The buffer must not be used after this is called.
    func deallocate() {
        try! rustCall { ffi_cooklang_bindings_rustbuffer_free(self, $0) }
    }
}

private extension ForeignBytes {
    init(bufferPointer: UnsafeBufferPointer<UInt8>) {
        self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress)
    }
}

// For every type used in the interface, we provide helper methods for conveniently
// lifting and lowering that type from C-compatible data, and for reading and writing
// values of that type in a buffer.

// Helper classes/extensions that don't change.
// Someday, this will be in a library of its own.

private extension Data {
    init(rustBuffer: RustBuffer) {
        self.init(
            bytesNoCopy: rustBuffer.data!,
            count: Int(rustBuffer.len),
            deallocator: .none
        )
    }
}

// Define reader functionality.  Normally this would be defined in a class or
// struct, but we use standalone functions instead in order to make external
// types work.
//
// With external types, one swift source file needs to be able to call the read
// method on another source file's FfiConverter, but then what visibility
// should Reader have?
// - If Reader is fileprivate, then this means the read() must also
//   be fileprivate, which doesn't work with external types.
// - If Reader is internal/public, we'll get compile errors since both source
//   files will try define the same type.
//
// Instead, the read() method and these helper functions input a tuple of data

private func createReader(data: Data) -> (data: Data, offset: Data.Index) {
    (data: data, offset: 0)
}

// Reads an integer at the current offset, in big-endian order, and advances
// the offset on success. Throws if reading the integer would move the
// offset past the end of the buffer.
private func readInt<T: FixedWidthInteger>(_ reader: inout (data: Data, offset: Data.Index)) throws -> T {
    let range = reader.offset ..< reader.offset + MemoryLayout<T>.size
    guard reader.data.count >= range.upperBound else {
        throw UniffiInternalError.bufferOverflow
    }
    if T.self == UInt8.self {
        let value = reader.data[reader.offset]
        reader.offset += 1
        return value as! T
    }
    var value: T = 0
    let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) }
    reader.offset = range.upperBound
    return value.bigEndian
}

// Reads an arbitrary number of bytes, to be used to read
// raw bytes, this is useful when lifting strings
private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] {
    let range = reader.offset ..< (reader.offset + count)
    guard reader.data.count >= range.upperBound else {
        throw UniffiInternalError.bufferOverflow
    }
    var value = [UInt8](repeating: 0, count: count)
    value.withUnsafeMutableBufferPointer { buffer in
        reader.data.copyBytes(to: buffer, from: range)
    }
    reader.offset = range.upperBound
    return value
}

// Reads a float at the current offset.
private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float {
    return try Float(bitPattern: readInt(&reader))
}

// Reads a float at the current offset.
private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double {
    return try Double(bitPattern: readInt(&reader))
}

// Indicates if the offset has reached the end of the buffer.
private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool {
    return reader.offset < reader.data.count
}

// Define writer functionality.  Normally this would be defined in a class or
// struct, but we use standalone functions instead in order to make external
// types work.  See the above discussion on Readers for details.

private func createWriter() -> [UInt8] {
    return []
}

private func writeBytes<S>(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 {
    writer.append(contentsOf: byteArr)
}

// Writes an integer in big-endian order.
//
// Warning: make sure what you are trying to write
// is in the correct type!
private func writeInt<T: FixedWidthInteger>(_ writer: inout [UInt8], _ value: T) {
    var value = value.bigEndian
    withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) }
}

private func writeFloat(_ writer: inout [UInt8], _ value: Float) {
    writeInt(&writer, value.bitPattern)
}

private func writeDouble(_ writer: inout [UInt8], _ value: Double) {
    writeInt(&writer, value.bitPattern)
}

// Protocol for types that transfer other types across the FFI. This is
// analogous to the Rust trait of the same name.
private protocol FfiConverter {
    associatedtype FfiType
    associatedtype SwiftType

    static func lift(_ value: FfiType) throws -> SwiftType
    static func lower(_ value: SwiftType) -> FfiType
    static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType
    static func write(_ value: SwiftType, into buf: inout [UInt8])
}

// Types conforming to `Primitive` pass themselves directly over the FFI.
private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {}

extension FfiConverterPrimitive {
    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public static func lift(_ value: FfiType) throws -> SwiftType {
        return value
    }

    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public static func lower(_ value: SwiftType) -> FfiType {
        return value
    }
}

// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`.
// Used for complex types where it's hard to write a custom lift/lower.
private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {}

extension FfiConverterRustBuffer {
    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public static func lift(_ buf: RustBuffer) throws -> SwiftType {
        var reader = createReader(data: Data(rustBuffer: buf))
        let value = try read(from: &reader)
        if hasRemaining(reader) {
            throw UniffiInternalError.incompleteData
        }
        buf.deallocate()
        return value
    }

    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public static func lower(_ value: SwiftType) -> RustBuffer {
        var writer = createWriter()
        write(value, into: &writer)
        return RustBuffer(bytes: writer)
    }
}

// An error type for FFI errors. These errors occur at the UniFFI level, not
// the library level.
private enum UniffiInternalError: LocalizedError {
    case bufferOverflow
    case incompleteData
    case unexpectedOptionalTag
    case unexpectedEnumCase
    case unexpectedNullPointer
    case unexpectedRustCallStatusCode
    case unexpectedRustCallError
    case unexpectedStaleHandle
    case rustPanic(_ message: String)

    public var errorDescription: String? {
        switch self {
        case .bufferOverflow: return "Reading the requested value would read past the end of the buffer"
        case .incompleteData: return "The buffer still has data after lifting its containing value"
        case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1"
        case .unexpectedEnumCase: return "Raw enum value doesn't match any cases"
        case .unexpectedNullPointer: return "Raw pointer value was null"
        case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code"
        case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified"
        case .unexpectedStaleHandle: return "The object in the handle map has been dropped already"
        case let .rustPanic(message): return message
        }
    }
}

private extension NSLock {
    func withLock<T>(f: () throws -> T) rethrows -> T {
        lock()
        defer { self.unlock() }
        return try f()
    }
}

private let CALL_SUCCESS: Int8 = 0
private let CALL_ERROR: Int8 = 1
private let CALL_UNEXPECTED_ERROR: Int8 = 2
private let CALL_CANCELLED: Int8 = 3

private extension RustCallStatus {
    init() {
        self.init(
            code: CALL_SUCCESS,
            errorBuf: RustBuffer(
                capacity: 0,
                len: 0,
                data: nil
            )
        )
    }
}

private func rustCall<T>(_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T {
    let neverThrow: ((RustBuffer) throws -> Never)? = nil
    return try makeRustCall(callback, errorHandler: neverThrow)
}

private func rustCallWithError<T, E: Swift.Error>(
    _ errorHandler: @escaping (RustBuffer) throws -> E,
    _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T
) throws -> T {
    try makeRustCall(callback, errorHandler: errorHandler)
}

private func makeRustCall<T, E: Swift.Error>(
    _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T,
    errorHandler: ((RustBuffer) throws -> E)?
) throws -> T {
    uniffiEnsureInitialized()
    var callStatus = RustCallStatus()
    let returnedVal = callback(&callStatus)
    try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler)
    return returnedVal
}

private func uniffiCheckCallStatus<E: Swift.Error>(
    callStatus: RustCallStatus,
    errorHandler: ((RustBuffer) throws -> E)?
) throws {
    switch callStatus.code {
    case CALL_SUCCESS:
        return

    case CALL_ERROR:
        if let errorHandler = errorHandler {
            throw try errorHandler(callStatus.errorBuf)
        } else {
            callStatus.errorBuf.deallocate()
            throw UniffiInternalError.unexpectedRustCallError
        }

    case CALL_UNEXPECTED_ERROR:
        // When the rust code sees a panic, it tries to construct a RustBuffer
        // with the message.  But if that code panics, then it just sends back
        // an empty buffer.
        if callStatus.errorBuf.len > 0 {
            throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf))
        } else {
            callStatus.errorBuf.deallocate()
            throw UniffiInternalError.rustPanic("Rust panic")
        }

    case CALL_CANCELLED:
        fatalError("Cancellation not supported yet")

    default:
        throw UniffiInternalError.unexpectedRustCallStatusCode
    }
}

private func uniffiTraitInterfaceCall<T>(
    callStatus: UnsafeMutablePointer<RustCallStatus>,
    makeCall: () throws -> T,
    writeReturn: (T) -> Void
) {
    do {
        try writeReturn(makeCall())
    } catch {
        callStatus.pointee.code = CALL_UNEXPECTED_ERROR
        callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error))
    }
}

private func uniffiTraitInterfaceCallWithError<T, E>(
    callStatus: UnsafeMutablePointer<RustCallStatus>,
    makeCall: () throws -> T,
    writeReturn: (T) -> Void,
    lowerError: (E) -> RustBuffer
) {
    do {
        try writeReturn(makeCall())
    } catch let error as E {
        callStatus.pointee.code = CALL_ERROR
        callStatus.pointee.errorBuf = lowerError(error)
    } catch {
        callStatus.pointee.code = CALL_UNEXPECTED_ERROR
        callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error))
    }
}

private class UniffiHandleMap<T> {
    private var map: [UInt64: T] = [:]
    private let lock = NSLock()
    private var currentHandle: UInt64 = 1

    func insert(obj: T) -> UInt64 {
        lock.withLock {
            let handle = currentHandle
            currentHandle += 1
            map[handle] = obj
            return handle
        }
    }

    func get(handle: UInt64) throws -> T {
        try lock.withLock {
            guard let obj = map[handle] else {
                throw UniffiInternalError.unexpectedStaleHandle
            }
            return obj
        }
    }

    @discardableResult
    func remove(handle: UInt64) throws -> T {
        try lock.withLock {
            guard let obj = map.removeValue(forKey: handle) else {
                throw UniffiInternalError.unexpectedStaleHandle
            }
            return obj
        }
    }

    var count: Int {
        map.count
    }
}

// Public interface members begin here.

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterUInt32: FfiConverterPrimitive {
    typealias FfiType = UInt32
    typealias SwiftType = UInt32

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 {
        return try lift(readInt(&buf))
    }

    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        writeInt(&buf, lower(value))
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterDouble: FfiConverterPrimitive {
    typealias FfiType = Double
    typealias SwiftType = Double

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Double {
        return try lift(readDouble(&buf))
    }

    public static func write(_ value: Double, into buf: inout [UInt8]) {
        writeDouble(&buf, lower(value))
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterString: FfiConverter {
    typealias SwiftType = String
    typealias FfiType = RustBuffer

    public static func lift(_ value: RustBuffer) throws -> String {
        defer {
            value.deallocate()
        }
        if value.data == nil {
            return String()
        }
        let bytes = UnsafeBufferPointer<UInt8>(start: value.data!, count: Int(value.len))
        return String(bytes: bytes, encoding: String.Encoding.utf8)!
    }

    public static func lower(_ value: String) -> RustBuffer {
        return value.utf8CString.withUnsafeBufferPointer { ptr in
            // The swift string gives us int8_t, we want uint8_t.
            ptr.withMemoryRebound(to: UInt8.self) { ptr in
                // The swift string gives us a trailing null byte, we don't want it.
                let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1))
                return RustBuffer.from(buf)
            }
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String {
        let len: Int32 = try readInt(&buf)
        return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)!
    }

    public static func write(_ value: String, into buf: inout [UInt8]) {
        let len = Int32(value.utf8.count)
        writeInt(&buf, len)
        writeBytes(&buf, value.utf8)
    }
}

/**
 * Configuration for organizing ingredients into shopping aisles
 */
public protocol AisleConfProtocol: AnyObject {
    /**
     * Returns the category name for a given ingredient
     *
     * # Arguments
     * * `ingredient_name` - The name of the ingredient to categorize
     *
     * # Returns
     * The category name if the ingredient is found, None otherwise
     */
    func categoryFor(ingredientName: String) -> String?
}

/**
 * Configuration for organizing ingredients into shopping aisles
 */
open class AisleConf:
    AisleConfProtocol
{
    fileprivate let pointer: UnsafeMutableRawPointer!

    /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly.
    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public struct NoPointer {
        public init() {}
    }

    // TODO: We'd like this to be `private` but for Swifty reasons,
    // we can't implement `FfiConverter` without making this `required` and we can't
    // make it `required` without making it `public`.
    public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
        self.pointer = pointer
    }

    // This constructor can be used to instantiate a fake object.
    // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject].
    //
    // - Warning:
    //     Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash.
    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public init(noPointer _: NoPointer) {
        pointer = nil
    }

    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public func uniffiClonePointer() -> UnsafeMutableRawPointer {
        return try! rustCall { uniffi_cooklang_bindings_fn_clone_aisleconf(self.pointer, $0) }
    }

    // No primary constructor declared for this class.

    deinit {
        guard let pointer = pointer else {
            return
        }

        try! rustCall { uniffi_cooklang_bindings_fn_free_aisleconf(pointer, $0) }
    }

    /**
     * Returns the category name for a given ingredient
     *
     * # Arguments
     * * `ingredient_name` - The name of the ingredient to categorize
     *
     * # Returns
     * The category name if the ingredient is found, None otherwise
     */
    open func categoryFor(ingredientName: String) -> String? {
        return try! FfiConverterOptionString.lift(try! rustCall {
            uniffi_cooklang_bindings_fn_method_aisleconf_category_for(self.uniffiClonePointer(),
                                                                      FfiConverterString.lower(ingredientName), $0)
        })
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeAisleConf: FfiConverter {
    typealias FfiType = UnsafeMutableRawPointer
    typealias SwiftType = AisleConf

    public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AisleConf {
        return AisleConf(unsafeFromRawPointer: pointer)
    }

    public static func lower(_ value: AisleConf) -> UnsafeMutableRawPointer {
        return value.uniffiClonePointer()
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AisleConf {
        let v: UInt64 = try readInt(&buf)
        // The Rust code won't compile if a pointer won't fit in a UInt64.
        // We have to go via `UInt` because that's the thing that's the size of a pointer.
        let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
        if ptr == nil {
            throw UniffiInternalError.unexpectedNullPointer
        }
        return try lift(ptr!)
    }

    public static func write(_ value: AisleConf, into buf: inout [UInt8]) {
        // This fiddling is because `Int` is the thing that's the same size as a pointer.
        // The Rust code won't compile if a pointer won't fit in a `UInt64`.
        writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value)))))
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeAisleConf_lift(_ pointer: UnsafeMutableRawPointer) throws -> AisleConf {
    return try FfiConverterTypeAisleConf.lift(pointer)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeAisleConf_lower(_ value: AisleConf) -> UnsafeMutableRawPointer {
    return FfiConverterTypeAisleConf.lower(value)
}

/**
 * A parsed Cooklang recipe containing all recipe components
 */
public protocol CooklangRecipeProtocol: AnyObject {
    /**
     * Returns all cookware used in the recipe
     */
    func cookware() -> [Cookware]

    /**
     * Returns all ingredients used in the recipe
     */
    func ingredients() -> [Ingredient]

    /**
     * Returns all sections in the recipe
     */
    func sections() -> [Section]

    /**
     * Returns all timers in the recipe
     */
    func timers() -> [Timer]
}

/**
 * A parsed Cooklang recipe containing all recipe components
 */
open class CooklangRecipe:
    CooklangRecipeProtocol
{
    fileprivate let pointer: UnsafeMutableRawPointer!

    /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly.
    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public struct NoPointer {
        public init() {}
    }

    // TODO: We'd like this to be `private` but for Swifty reasons,
    // we can't implement `FfiConverter` without making this `required` and we can't
    // make it `required` without making it `public`.
    public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
        self.pointer = pointer
    }

    // This constructor can be used to instantiate a fake object.
    // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject].
    //
    // - Warning:
    //     Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash.
    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public init(noPointer _: NoPointer) {
        pointer = nil
    }

    #if swift(>=5.8)
        @_documentation(visibility: private)
    #endif
    public func uniffiClonePointer() -> UnsafeMutableRawPointer {
        return try! rustCall { uniffi_cooklang_bindings_fn_clone_cooklangrecipe(self.pointer, $0) }
    }

    // No primary constructor declared for this class.

    deinit {
        guard let pointer = pointer else {
            return
        }

        try! rustCall { uniffi_cooklang_bindings_fn_free_cooklangrecipe(pointer, $0) }
    }

    /**
     * Returns all cookware used in the recipe
     */
    open func cookware() -> [Cookware] {
        return try! FfiConverterSequenceTypeCookware.lift(try! rustCall {
            uniffi_cooklang_bindings_fn_method_cooklangrecipe_cookware(self.uniffiClonePointer(), $0)
        })
    }

    /**
     * Returns all ingredients used in the recipe
     */
    open func ingredients() -> [Ingredient] {
        return try! FfiConverterSequenceTypeIngredient.lift(try! rustCall {
            uniffi_cooklang_bindings_fn_method_cooklangrecipe_ingredients(self.uniffiClonePointer(), $0)
        })
    }

    /**
     * Returns all sections in the recipe
     */
    open func sections() -> [Section] {
        return try! FfiConverterSequenceTypeSection.lift(try! rustCall {
            uniffi_cooklang_bindings_fn_method_cooklangrecipe_sections(self.uniffiClonePointer(), $0)
        })
    }

    /**
     * Returns all timers in the recipe
     */
    open func timers() -> [Timer] {
        return try! FfiConverterSequenceTypeTimer.lift(try! rustCall {
            uniffi_cooklang_bindings_fn_method_cooklangrecipe_timers(self.uniffiClonePointer(), $0)
        })
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeCooklangRecipe: FfiConverter {
    typealias FfiType = UnsafeMutableRawPointer
    typealias SwiftType = CooklangRecipe

    public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> CooklangRecipe {
        return CooklangRecipe(unsafeFromRawPointer: pointer)
    }

    public static func lower(_ value: CooklangRecipe) -> UnsafeMutableRawPointer {
        return value.uniffiClonePointer()
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CooklangRecipe {
        let v: UInt64 = try readInt(&buf)
        // The Rust code won't compile if a pointer won't fit in a UInt64.
        // We have to go via `UInt` because that's the thing that's the size of a pointer.
        let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
        if ptr == nil {
            throw UniffiInternalError.unexpectedNullPointer
        }
        return try lift(ptr!)
    }

    public static func write(_ value: CooklangRecipe, into buf: inout [UInt8]) {
        // This fiddling is because `Int` is the thing that's the same size as a pointer.
        // The Rust code won't compile if a pointer won't fit in a `UInt64`.
        writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value)))))
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeCooklangRecipe_lift(_ pointer: UnsafeMutableRawPointer) throws -> CooklangRecipe {
    return try FfiConverterTypeCooklangRecipe.lift(pointer)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeCooklangRecipe_lower(_ value: CooklangRecipe) -> UnsafeMutableRawPointer {
    return FfiConverterTypeCooklangRecipe.lower(value)
}

/**
 * A shopping aisle category containing related ingredients
 */
public struct AisleCategory {
    public let name: String
    public let ingredients: [AisleIngredient]

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(name: String, ingredients: [AisleIngredient]) {
        self.name = name
        self.ingredients = ingredients
    }
}

extension AisleCategory: Equatable, Hashable {
    public static func == (lhs: AisleCategory, rhs: AisleCategory) -> Bool {
        if lhs.name != rhs.name {
            return false
        }
        if lhs.ingredients != rhs.ingredients {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(ingredients)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeAisleCategory: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AisleCategory {
        return
            try AisleCategory(
                name: FfiConverterString.read(from: &buf),
                ingredients: FfiConverterSequenceTypeAisleIngredient.read(from: &buf)
            )
    }

    public static func write(_ value: AisleCategory, into buf: inout [UInt8]) {
        FfiConverterString.write(value.name, into: &buf)
        FfiConverterSequenceTypeAisleIngredient.write(value.ingredients, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeAisleCategory_lift(_ buf: RustBuffer) throws -> AisleCategory {
    return try FfiConverterTypeAisleCategory.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeAisleCategory_lower(_ value: AisleCategory) -> RustBuffer {
    return FfiConverterTypeAisleCategory.lower(value)
}

/**
 * An ingredient with its name and aliases for aisle categorization
 */
public struct AisleIngredient {
    public let name: String
    public let aliases: [String]

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(name: String, aliases: [String]) {
        self.name = name
        self.aliases = aliases
    }
}

extension AisleIngredient: Equatable, Hashable {
    public static func == (lhs: AisleIngredient, rhs: AisleIngredient) -> Bool {
        if lhs.name != rhs.name {
            return false
        }
        if lhs.aliases != rhs.aliases {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(aliases)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeAisleIngredient: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AisleIngredient {
        return
            try AisleIngredient(
                name: FfiConverterString.read(from: &buf),
                aliases: FfiConverterSequenceString.read(from: &buf)
            )
    }

    public static func write(_ value: AisleIngredient, into buf: inout [UInt8]) {
        FfiConverterString.write(value.name, into: &buf)
        FfiConverterSequenceString.write(value.aliases, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeAisleIngredient_lift(_ buf: RustBuffer) throws -> AisleIngredient {
    return try FfiConverterTypeAisleIngredient.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeAisleIngredient_lower(_ value: AisleIngredient) -> RustBuffer {
    return FfiConverterTypeAisleIngredient.lower(value)
}

/**
 * Represents a quantity with optional units
 */
public struct Amount {
    public let quantity: Value
    public let units: String?

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(quantity: Value, units: String?) {
        self.quantity = quantity
        self.units = units
    }
}

extension Amount: Equatable, Hashable {
    public static func == (lhs: Amount, rhs: Amount) -> Bool {
        if lhs.quantity != rhs.quantity {
            return false
        }
        if lhs.units != rhs.units {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(quantity)
        hasher.combine(units)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeAmount: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Amount {
        return
            try Amount(
                quantity: FfiConverterTypeValue.read(from: &buf),
                units: FfiConverterOptionString.read(from: &buf)
            )
    }

    public static func write(_ value: Amount, into buf: inout [UInt8]) {
        FfiConverterTypeValue.write(value.quantity, into: &buf)
        FfiConverterOptionString.write(value.units, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeAmount_lift(_ buf: RustBuffer) throws -> Amount {
    return try FfiConverterTypeAmount.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeAmount_lower(_ value: Amount) -> RustBuffer {
    return FfiConverterTypeAmount.lower(value)
}

/**
 * A text note within the recipe
 */
public struct BlockNote {
    public let text: String

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(text: String) {
        self.text = text
    }
}

extension BlockNote: Equatable, Hashable {
    public static func == (lhs: BlockNote, rhs: BlockNote) -> Bool {
        if lhs.text != rhs.text {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(text)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeBlockNote: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BlockNote {
        return
            try BlockNote(
                text: FfiConverterString.read(from: &buf)
            )
    }

    public static func write(_ value: BlockNote, into buf: inout [UInt8]) {
        FfiConverterString.write(value.text, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeBlockNote_lift(_ buf: RustBuffer) throws -> BlockNote {
    return try FfiConverterTypeBlockNote.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeBlockNote_lower(_ value: BlockNote) -> RustBuffer {
    return FfiConverterTypeBlockNote.lower(value)
}

/**
 * Represents a piece of cookware used in the recipe
 */
public struct Cookware {
    public let name: String
    public let amount: Amount?

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(name: String, amount: Amount?) {
        self.name = name
        self.amount = amount
    }
}

extension Cookware: Equatable, Hashable {
    public static func == (lhs: Cookware, rhs: Cookware) -> Bool {
        if lhs.name != rhs.name {
            return false
        }
        if lhs.amount != rhs.amount {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(amount)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeCookware: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Cookware {
        return
            try Cookware(
                name: FfiConverterString.read(from: &buf),
                amount: FfiConverterOptionTypeAmount.read(from: &buf)
            )
    }

    public static func write(_ value: Cookware, into buf: inout [UInt8]) {
        FfiConverterString.write(value.name, into: &buf)
        FfiConverterOptionTypeAmount.write(value.amount, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeCookware_lift(_ buf: RustBuffer) throws -> Cookware {
    return try FfiConverterTypeCookware.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeCookware_lower(_ value: Cookware) -> RustBuffer {
    return FfiConverterTypeCookware.lower(value)
}

/**
 * Key for grouping quantities by unit and type
 */
public struct GroupedQuantityKey {
    public let name: String
    public let unitType: QuantityType

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(name: String, unitType: QuantityType) {
        self.name = name
        self.unitType = unitType
    }
}

extension GroupedQuantityKey: Equatable, Hashable {
    public static func == (lhs: GroupedQuantityKey, rhs: GroupedQuantityKey) -> Bool {
        if lhs.name != rhs.name {
            return false
        }
        if lhs.unitType != rhs.unitType {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(unitType)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeGroupedQuantityKey: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> GroupedQuantityKey {
        return
            try GroupedQuantityKey(
                name: FfiConverterString.read(from: &buf),
                unitType: FfiConverterTypeQuantityType.read(from: &buf)
            )
    }

    public static func write(_ value: GroupedQuantityKey, into buf: inout [UInt8]) {
        FfiConverterString.write(value.name, into: &buf)
        FfiConverterTypeQuantityType.write(value.unitType, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeGroupedQuantityKey_lift(_ buf: RustBuffer) throws -> GroupedQuantityKey {
    return try FfiConverterTypeGroupedQuantityKey.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeGroupedQuantityKey_lower(_ value: GroupedQuantityKey) -> RustBuffer {
    return FfiConverterTypeGroupedQuantityKey.lower(value)
}

/**
 * Represents an ingredient in the recipe
 */
public struct Ingredient {
    public let name: String
    public let amount: Amount?
    public let descriptor: String?

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(name: String, amount: Amount?, descriptor: String?) {
        self.name = name
        self.amount = amount
        self.descriptor = descriptor
    }
}

extension Ingredient: Equatable, Hashable {
    public static func == (lhs: Ingredient, rhs: Ingredient) -> Bool {
        if lhs.name != rhs.name {
            return false
        }
        if lhs.amount != rhs.amount {
            return false
        }
        if lhs.descriptor != rhs.descriptor {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(amount)
        hasher.combine(descriptor)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeIngredient: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Ingredient {
        return
            try Ingredient(
                name: FfiConverterString.read(from: &buf),
                amount: FfiConverterOptionTypeAmount.read(from: &buf),
                descriptor: FfiConverterOptionString.read(from: &buf)
            )
    }

    public static func write(_ value: Ingredient, into buf: inout [UInt8]) {
        FfiConverterString.write(value.name, into: &buf)
        FfiConverterOptionTypeAmount.write(value.amount, into: &buf)
        FfiConverterOptionString.write(value.descriptor, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeIngredient_lift(_ buf: RustBuffer) throws -> Ingredient {
    return try FfiConverterTypeIngredient.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeIngredient_lower(_ value: Ingredient) -> RustBuffer {
    return FfiConverterTypeIngredient.lower(value)
}

/**
 * A name with an optional URL (used for author/source)
 */
public struct NameAndUrl {
    public let name: String?
    public let url: String?

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(name: String?, url: String?) {
        self.name = name
        self.url = url
    }
}

extension NameAndUrl: Equatable, Hashable {
    public static func == (lhs: NameAndUrl, rhs: NameAndUrl) -> Bool {
        if lhs.name != rhs.name {
            return false
        }
        if lhs.url != rhs.url {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(url)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeNameAndUrl: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NameAndUrl {
        return
            try NameAndUrl(
                name: FfiConverterOptionString.read(from: &buf),
                url: FfiConverterOptionString.read(from: &buf)
            )
    }

    public static func write(_ value: NameAndUrl, into buf: inout [UInt8]) {
        FfiConverterOptionString.write(value.name, into: &buf)
        FfiConverterOptionString.write(value.url, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeNameAndUrl_lift(_ buf: RustBuffer) throws -> NameAndUrl {
    return try FfiConverterTypeNameAndUrl.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeNameAndUrl_lower(_ value: NameAndUrl) -> RustBuffer {
    return FfiConverterTypeNameAndUrl.lower(value)
}

/**
 * Represents a distinct section of a recipe, optionally with a title
 */
public struct Section {
    public let title: String?
    public let blocks: [Block]
    public let ingredientRefs: [UInt32]
    public let cookwareRefs: [UInt32]
    public let timerRefs: [UInt32]

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(title: String?, blocks: [Block], ingredientRefs: [UInt32], cookwareRefs: [UInt32], timerRefs: [UInt32]) {
        self.title = title
        self.blocks = blocks
        self.ingredientRefs = ingredientRefs
        self.cookwareRefs = cookwareRefs
        self.timerRefs = timerRefs
    }
}

extension Section: Equatable, Hashable {
    public static func == (lhs: Section, rhs: Section) -> Bool {
        if lhs.title != rhs.title {
            return false
        }
        if lhs.blocks != rhs.blocks {
            return false
        }
        if lhs.ingredientRefs != rhs.ingredientRefs {
            return false
        }
        if lhs.cookwareRefs != rhs.cookwareRefs {
            return false
        }
        if lhs.timerRefs != rhs.timerRefs {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(title)
        hasher.combine(blocks)
        hasher.combine(ingredientRefs)
        hasher.combine(cookwareRefs)
        hasher.combine(timerRefs)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeSection: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Section {
        return
            try Section(
                title: FfiConverterOptionString.read(from: &buf),
                blocks: FfiConverterSequenceTypeBlock.read(from: &buf),
                ingredientRefs: FfiConverterSequenceUInt32.read(from: &buf),
                cookwareRefs: FfiConverterSequenceUInt32.read(from: &buf),
                timerRefs: FfiConverterSequenceUInt32.read(from: &buf)
            )
    }

    public static func write(_ value: Section, into buf: inout [UInt8]) {
        FfiConverterOptionString.write(value.title, into: &buf)
        FfiConverterSequenceTypeBlock.write(value.blocks, into: &buf)
        FfiConverterSequenceUInt32.write(value.ingredientRefs, into: &buf)
        FfiConverterSequenceUInt32.write(value.cookwareRefs, into: &buf)
        FfiConverterSequenceUInt32.write(value.timerRefs, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeSection_lift(_ buf: RustBuffer) throws -> Section {
    return try FfiConverterTypeSection.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeSection_lower(_ value: Section) -> RustBuffer {
    return FfiConverterTypeSection.lower(value)
}

/**
 * Represents a single cooking instruction step
 */
public struct Step {
    public let items: [Item]
    public let ingredientRefs: [UInt32]
    public let cookwareRefs: [UInt32]
    public let timerRefs: [UInt32]

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(items: [Item], ingredientRefs: [UInt32], cookwareRefs: [UInt32], timerRefs: [UInt32]) {
        self.items = items
        self.ingredientRefs = ingredientRefs
        self.cookwareRefs = cookwareRefs
        self.timerRefs = timerRefs
    }
}

extension Step: Equatable, Hashable {
    public static func == (lhs: Step, rhs: Step) -> Bool {
        if lhs.items != rhs.items {
            return false
        }
        if lhs.ingredientRefs != rhs.ingredientRefs {
            return false
        }
        if lhs.cookwareRefs != rhs.cookwareRefs {
            return false
        }
        if lhs.timerRefs != rhs.timerRefs {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(items)
        hasher.combine(ingredientRefs)
        hasher.combine(cookwareRefs)
        hasher.combine(timerRefs)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeStep: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Step {
        return
            try Step(
                items: FfiConverterSequenceTypeItem.read(from: &buf),
                ingredientRefs: FfiConverterSequenceUInt32.read(from: &buf),
                cookwareRefs: FfiConverterSequenceUInt32.read(from: &buf),
                timerRefs: FfiConverterSequenceUInt32.read(from: &buf)
            )
    }

    public static func write(_ value: Step, into buf: inout [UInt8]) {
        FfiConverterSequenceTypeItem.write(value.items, into: &buf)
        FfiConverterSequenceUInt32.write(value.ingredientRefs, into: &buf)
        FfiConverterSequenceUInt32.write(value.cookwareRefs, into: &buf)
        FfiConverterSequenceUInt32.write(value.timerRefs, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeStep_lift(_ buf: RustBuffer) throws -> Step {
    return try FfiConverterTypeStep.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeStep_lower(_ value: Step) -> RustBuffer {
    return FfiConverterTypeStep.lower(value)
}

/**
 * Represents a timer in the recipe
 */
public struct Timer {
    public let name: String?
    public let amount: Amount?

    // Default memberwise initializers are never public by default, so we
    // declare one manually.
    public init(name: String?, amount: Amount?) {
        self.name = name
        self.amount = amount
    }
}

extension Timer: Equatable, Hashable {
    public static func == (lhs: Timer, rhs: Timer) -> Bool {
        if lhs.name != rhs.name {
            return false
        }
        if lhs.amount != rhs.amount {
            return false
        }
        return true
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(amount)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeTimer: FfiConverterRustBuffer {
    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Timer {
        return
            try Timer(
                name: FfiConverterOptionString.read(from: &buf),
                amount: FfiConverterOptionTypeAmount.read(from: &buf)
            )
    }

    public static func write(_ value: Timer, into buf: inout [UInt8]) {
        FfiConverterOptionString.write(value.name, into: &buf)
        FfiConverterOptionTypeAmount.write(value.amount, into: &buf)
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeTimer_lift(_ buf: RustBuffer) throws -> Timer {
    return try FfiConverterTypeTimer.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeTimer_lower(_ value: Timer) -> RustBuffer {
    return FfiConverterTypeTimer.lower(value)
}

// Note that we don't yet support `indirect` for enums.
// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
/**
 * A block can either be a cooking step or a note
 */

public enum Block {
    case stepBlock(Step
    )
    case noteBlock(BlockNote
    )
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeBlock: FfiConverterRustBuffer {
    typealias SwiftType = Block

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Block {
        let variant: Int32 = try readInt(&buf)
        switch variant {
        case 1: return try .stepBlock(FfiConverterTypeStep.read(from: &buf)
            )

        case 2: return try .noteBlock(FfiConverterTypeBlockNote.read(from: &buf)
            )

        default: throw UniffiInternalError.unexpectedEnumCase
        }
    }

    public static func write(_ value: Block, into buf: inout [UInt8]) {
        switch value {
        case let .stepBlock(v1):
            writeInt(&buf, Int32(1))
            FfiConverterTypeStep.write(v1, into: &buf)

        case let .noteBlock(v1):
            writeInt(&buf, Int32(2))
            FfiConverterTypeBlockNote.write(v1, into: &buf)
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeBlock_lift(_ buf: RustBuffer) throws -> Block {
    return try FfiConverterTypeBlock.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeBlock_lower(_ value: Block) -> RustBuffer {
    return FfiConverterTypeBlock.lower(value)
}

extension Block: Equatable, Hashable {}

// Note that we don't yet support `indirect` for enums.
// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
/**
 * Types of components that can be referenced in a recipe
 */

public enum Component {
    case ingredientComponent(Ingredient
    )
    case cookwareComponent(Cookware
    )
    case timerComponent(Timer
    )
    case textComponent(String
    )
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeComponent: FfiConverterRustBuffer {
    typealias SwiftType = Component

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Component {
        let variant: Int32 = try readInt(&buf)
        switch variant {
        case 1: return try .ingredientComponent(FfiConverterTypeIngredient.read(from: &buf)
            )

        case 2: return try .cookwareComponent(FfiConverterTypeCookware.read(from: &buf)
            )

        case 3: return try .timerComponent(FfiConverterTypeTimer.read(from: &buf)
            )

        case 4: return try .textComponent(FfiConverterString.read(from: &buf)
            )

        default: throw UniffiInternalError.unexpectedEnumCase
        }
    }

    public static func write(_ value: Component, into buf: inout [UInt8]) {
        switch value {
        case let .ingredientComponent(v1):
            writeInt(&buf, Int32(1))
            FfiConverterTypeIngredient.write(v1, into: &buf)

        case let .cookwareComponent(v1):
            writeInt(&buf, Int32(2))
            FfiConverterTypeCookware.write(v1, into: &buf)

        case let .timerComponent(v1):
            writeInt(&buf, Int32(3))
            FfiConverterTypeTimer.write(v1, into: &buf)

        case let .textComponent(v1):
            writeInt(&buf, Int32(4))
            FfiConverterString.write(v1, into: &buf)
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeComponent_lift(_ buf: RustBuffer) throws -> Component {
    return try FfiConverterTypeComponent.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeComponent_lower(_ value: Component) -> RustBuffer {
    return FfiConverterTypeComponent.lower(value)
}

extension Component: Equatable, Hashable {}

// Note that we don't yet support `indirect` for enums.
// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
/**
 * Elements that can appear in a recipe step
 */

public enum Item {
    case text(value: String
    )
    case ingredientRef(index: UInt32
    )
    case cookwareRef(index: UInt32
    )
    case timerRef(index: UInt32
    )
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeItem: FfiConverterRustBuffer {
    typealias SwiftType = Item

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Item {
        let variant: Int32 = try readInt(&buf)
        switch variant {
        case 1: return try .text(value: FfiConverterString.read(from: &buf)
            )

        case 2: return try .ingredientRef(index: FfiConverterUInt32.read(from: &buf)
            )

        case 3: return try .cookwareRef(index: FfiConverterUInt32.read(from: &buf)
            )

        case 4: return try .timerRef(index: FfiConverterUInt32.read(from: &buf)
            )

        default: throw UniffiInternalError.unexpectedEnumCase
        }
    }

    public static func write(_ value: Item, into buf: inout [UInt8]) {
        switch value {
        case let .text(value):
            writeInt(&buf, Int32(1))
            FfiConverterString.write(value, into: &buf)

        case let .ingredientRef(index):
            writeInt(&buf, Int32(2))
            FfiConverterUInt32.write(index, into: &buf)

        case let .cookwareRef(index):
            writeInt(&buf, Int32(3))
            FfiConverterUInt32.write(index, into: &buf)

        case let .timerRef(index):
            writeInt(&buf, Int32(4))
            FfiConverterUInt32.write(index, into: &buf)
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeItem_lift(_ buf: RustBuffer) throws -> Item {
    return try FfiConverterTypeItem.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeItem_lower(_ value: Item) -> RustBuffer {
    return FfiConverterTypeItem.lower(value)
}

extension Item: Equatable, Hashable {}

// Note that we don't yet support `indirect` for enums.
// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
/**
 * Type of quantity value in a grouped quantity
 */

public enum QuantityType {
    case number
    case range
    case text
    case empty
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeQuantityType: FfiConverterRustBuffer {
    typealias SwiftType = QuantityType

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> QuantityType {
        let variant: Int32 = try readInt(&buf)
        switch variant {
        case 1: return .number

        case 2: return .range

        case 3: return .text

        case 4: return .empty

        default: throw UniffiInternalError.unexpectedEnumCase
        }
    }

    public static func write(_ value: QuantityType, into buf: inout [UInt8]) {
        switch value {
        case .number:
            writeInt(&buf, Int32(1))

        case .range:
            writeInt(&buf, Int32(2))

        case .text:
            writeInt(&buf, Int32(3))

        case .empty:
            writeInt(&buf, Int32(4))
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeQuantityType_lift(_ buf: RustBuffer) throws -> QuantityType {
    return try FfiConverterTypeQuantityType.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeQuantityType_lower(_ value: QuantityType) -> RustBuffer {
    return FfiConverterTypeQuantityType.lower(value)
}

extension QuantityType: Equatable, Hashable {}

// Note that we don't yet support `indirect` for enums.
// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
/**
 * Recipe time as either total minutes or separate prep/cook times
 */

public enum RecipeTime {
    case total(minutes: UInt32
    )
    case composed(prepTime: UInt32?, cookTime: UInt32?)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeRecipeTime: FfiConverterRustBuffer {
    typealias SwiftType = RecipeTime

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> RecipeTime {
        let variant: Int32 = try readInt(&buf)
        switch variant {
        case 1: return try .total(minutes: FfiConverterUInt32.read(from: &buf)
            )

        case 2: return try .composed(prepTime: FfiConverterOptionUInt32.read(from: &buf), cookTime: FfiConverterOptionUInt32.read(from: &buf))

        default: throw UniffiInternalError.unexpectedEnumCase
        }
    }

    public static func write(_ value: RecipeTime, into buf: inout [UInt8]) {
        switch value {
        case let .total(minutes):
            writeInt(&buf, Int32(1))
            FfiConverterUInt32.write(minutes, into: &buf)

        case let .composed(prepTime, cookTime):
            writeInt(&buf, Int32(2))
            FfiConverterOptionUInt32.write(prepTime, into: &buf)
            FfiConverterOptionUInt32.write(cookTime, into: &buf)
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeRecipeTime_lift(_ buf: RustBuffer) throws -> RecipeTime {
    return try FfiConverterTypeRecipeTime.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeRecipeTime_lower(_ value: RecipeTime) -> RustBuffer {
    return FfiConverterTypeRecipeTime.lower(value)
}

extension RecipeTime: Equatable, Hashable {}

// Note that we don't yet support `indirect` for enums.
// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
/**
 * Recipe servings as either a number or text description
 */

public enum Servings {
    case number(value: UInt32
    )
    case text(value: String
    )
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeServings: FfiConverterRustBuffer {
    typealias SwiftType = Servings

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Servings {
        let variant: Int32 = try readInt(&buf)
        switch variant {
        case 1: return try .number(value: FfiConverterUInt32.read(from: &buf)
            )

        case 2: return try .text(value: FfiConverterString.read(from: &buf)
            )

        default: throw UniffiInternalError.unexpectedEnumCase
        }
    }

    public static func write(_ value: Servings, into buf: inout [UInt8]) {
        switch value {
        case let .number(value):
            writeInt(&buf, Int32(1))
            FfiConverterUInt32.write(value, into: &buf)

        case let .text(value):
            writeInt(&buf, Int32(2))
            FfiConverterString.write(value, into: &buf)
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeServings_lift(_ buf: RustBuffer) throws -> Servings {
    return try FfiConverterTypeServings.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeServings_lower(_ value: Servings) -> RustBuffer {
    return FfiConverterTypeServings.lower(value)
}

extension Servings: Equatable, Hashable {}

// Note that we don't yet support `indirect` for enums.
// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
/**
 * Standard metadata keys from the Cooklang specification
 */

public enum StdKey {
    case title
    case description
    case tags
    case author
    case source
    case course
    case time
    case prepTime
    case cookTime
    case servings
    case difficulty
    case cuisine
    case diet
    case images
    case locale
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeStdKey: FfiConverterRustBuffer {
    typealias SwiftType = StdKey

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> StdKey {
        let variant: Int32 = try readInt(&buf)
        switch variant {
        case 1: return .title

        case 2: return .description

        case 3: return .tags

        case 4: return .author

        case 5: return .source

        case 6: return .course

        case 7: return .time

        case 8: return .prepTime

        case 9: return .cookTime

        case 10: return .servings

        case 11: return .difficulty

        case 12: return .cuisine

        case 13: return .diet

        case 14: return .images

        case 15: return .locale

        default: throw UniffiInternalError.unexpectedEnumCase
        }
    }

    public static func write(_ value: StdKey, into buf: inout [UInt8]) {
        switch value {
        case .title:
            writeInt(&buf, Int32(1))

        case .description:
            writeInt(&buf, Int32(2))

        case .tags:
            writeInt(&buf, Int32(3))

        case .author:
            writeInt(&buf, Int32(4))

        case .source:
            writeInt(&buf, Int32(5))

        case .course:
            writeInt(&buf, Int32(6))

        case .time:
            writeInt(&buf, Int32(7))

        case .prepTime:
            writeInt(&buf, Int32(8))

        case .cookTime:
            writeInt(&buf, Int32(9))

        case .servings:
            writeInt(&buf, Int32(10))

        case .difficulty:
            writeInt(&buf, Int32(11))

        case .cuisine:
            writeInt(&buf, Int32(12))

        case .diet:
            writeInt(&buf, Int32(13))

        case .images:
            writeInt(&buf, Int32(14))

        case .locale:
            writeInt(&buf, Int32(15))
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeStdKey_lift(_ buf: RustBuffer) throws -> StdKey {
    return try FfiConverterTypeStdKey.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeStdKey_lower(_ value: StdKey) -> RustBuffer {
    return FfiConverterTypeStdKey.lower(value)
}

extension StdKey: Equatable, Hashable {}

// Note that we don't yet support `indirect` for enums.
// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
/**
 * Types of values that can represent quantities
 */

public enum Value {
    case number(value: Double
    )
    case range(start: Double, end: Double)
    case text(value: String
    )
    case empty
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public struct FfiConverterTypeValue: FfiConverterRustBuffer {
    typealias SwiftType = Value

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Value {
        let variant: Int32 = try readInt(&buf)
        switch variant {
        case 1: return try .number(value: FfiConverterDouble.read(from: &buf)
            )

        case 2: return try .range(start: FfiConverterDouble.read(from: &buf), end: FfiConverterDouble.read(from: &buf))

        case 3: return try .text(value: FfiConverterString.read(from: &buf)
            )

        case 4: return .empty

        default: throw UniffiInternalError.unexpectedEnumCase
        }
    }

    public static func write(_ value: Value, into buf: inout [UInt8]) {
        switch value {
        case let .number(value):
            writeInt(&buf, Int32(1))
            FfiConverterDouble.write(value, into: &buf)

        case let .range(start, end):
            writeInt(&buf, Int32(2))
            FfiConverterDouble.write(start, into: &buf)
            FfiConverterDouble.write(end, into: &buf)

        case let .text(value):
            writeInt(&buf, Int32(3))
            FfiConverterString.write(value, into: &buf)

        case .empty:
            writeInt(&buf, Int32(4))
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeValue_lift(_ buf: RustBuffer) throws -> Value {
    return try FfiConverterTypeValue.lift(buf)
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
public func FfiConverterTypeValue_lower(_ value: Value) -> RustBuffer {
    return FfiConverterTypeValue.lower(value)
}

extension Value: Equatable, Hashable {}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterOptionUInt32: FfiConverterRustBuffer {
    typealias SwiftType = UInt32?

    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        guard let value = value else {
            writeInt(&buf, Int8(0))
            return
        }
        writeInt(&buf, Int8(1))
        FfiConverterUInt32.write(value, into: &buf)
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
        switch try readInt(&buf) as Int8 {
        case 0: return nil
        case 1: return try FfiConverterUInt32.read(from: &buf)
        default: throw UniffiInternalError.unexpectedOptionalTag
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterOptionString: FfiConverterRustBuffer {
    typealias SwiftType = String?

    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        guard let value = value else {
            writeInt(&buf, Int8(0))
            return
        }
        writeInt(&buf, Int8(1))
        FfiConverterString.write(value, into: &buf)
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
        switch try readInt(&buf) as Int8 {
        case 0: return nil
        case 1: return try FfiConverterString.read(from: &buf)
        default: throw UniffiInternalError.unexpectedOptionalTag
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterOptionTypeAmount: FfiConverterRustBuffer {
    typealias SwiftType = Amount?

    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        guard let value = value else {
            writeInt(&buf, Int8(0))
            return
        }
        writeInt(&buf, Int8(1))
        FfiConverterTypeAmount.write(value, into: &buf)
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
        switch try readInt(&buf) as Int8 {
        case 0: return nil
        case 1: return try FfiConverterTypeAmount.read(from: &buf)
        default: throw UniffiInternalError.unexpectedOptionalTag
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterOptionTypeNameAndUrl: FfiConverterRustBuffer {
    typealias SwiftType = NameAndUrl?

    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        guard let value = value else {
            writeInt(&buf, Int8(0))
            return
        }
        writeInt(&buf, Int8(1))
        FfiConverterTypeNameAndUrl.write(value, into: &buf)
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
        switch try readInt(&buf) as Int8 {
        case 0: return nil
        case 1: return try FfiConverterTypeNameAndUrl.read(from: &buf)
        default: throw UniffiInternalError.unexpectedOptionalTag
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterOptionTypeRecipeTime: FfiConverterRustBuffer {
    typealias SwiftType = RecipeTime?

    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        guard let value = value else {
            writeInt(&buf, Int8(0))
            return
        }
        writeInt(&buf, Int8(1))
        FfiConverterTypeRecipeTime.write(value, into: &buf)
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
        switch try readInt(&buf) as Int8 {
        case 0: return nil
        case 1: return try FfiConverterTypeRecipeTime.read(from: &buf)
        default: throw UniffiInternalError.unexpectedOptionalTag
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterOptionTypeServings: FfiConverterRustBuffer {
    typealias SwiftType = Servings?

    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        guard let value = value else {
            writeInt(&buf, Int8(0))
            return
        }
        writeInt(&buf, Int8(1))
        FfiConverterTypeServings.write(value, into: &buf)
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
        switch try readInt(&buf) as Int8 {
        case 0: return nil
        case 1: return try FfiConverterTypeServings.read(from: &buf)
        default: throw UniffiInternalError.unexpectedOptionalTag
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterOptionSequenceString: FfiConverterRustBuffer {
    typealias SwiftType = [String]?

    public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
        guard let value = value else {
            writeInt(&buf, Int8(0))
            return
        }
        writeInt(&buf, Int8(1))
        FfiConverterSequenceString.write(value, into: &buf)
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
        switch try readInt(&buf) as Int8 {
        case 0: return nil
        case 1: return try FfiConverterSequenceString.read(from: &buf)
        default: throw UniffiInternalError.unexpectedOptionalTag
        }
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceUInt32: FfiConverterRustBuffer {
    typealias SwiftType = [UInt32]

    public static func write(_ value: [UInt32], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterUInt32.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt32] {
        let len: Int32 = try readInt(&buf)
        var seq = [UInt32]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterUInt32.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceString: FfiConverterRustBuffer {
    typealias SwiftType = [String]

    public static func write(_ value: [String], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterString.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String] {
        let len: Int32 = try readInt(&buf)
        var seq = [String]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterString.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceTypeAisleIngredient: FfiConverterRustBuffer {
    typealias SwiftType = [AisleIngredient]

    public static func write(_ value: [AisleIngredient], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterTypeAisleIngredient.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [AisleIngredient] {
        let len: Int32 = try readInt(&buf)
        var seq = [AisleIngredient]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterTypeAisleIngredient.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceTypeCookware: FfiConverterRustBuffer {
    typealias SwiftType = [Cookware]

    public static func write(_ value: [Cookware], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterTypeCookware.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Cookware] {
        let len: Int32 = try readInt(&buf)
        var seq = [Cookware]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterTypeCookware.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceTypeIngredient: FfiConverterRustBuffer {
    typealias SwiftType = [Ingredient]

    public static func write(_ value: [Ingredient], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterTypeIngredient.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Ingredient] {
        let len: Int32 = try readInt(&buf)
        var seq = [Ingredient]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterTypeIngredient.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceTypeSection: FfiConverterRustBuffer {
    typealias SwiftType = [Section]

    public static func write(_ value: [Section], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterTypeSection.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Section] {
        let len: Int32 = try readInt(&buf)
        var seq = [Section]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterTypeSection.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceTypeTimer: FfiConverterRustBuffer {
    typealias SwiftType = [Timer]

    public static func write(_ value: [Timer], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterTypeTimer.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Timer] {
        let len: Int32 = try readInt(&buf)
        var seq = [Timer]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterTypeTimer.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceTypeBlock: FfiConverterRustBuffer {
    typealias SwiftType = [Block]

    public static func write(_ value: [Block], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterTypeBlock.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Block] {
        let len: Int32 = try readInt(&buf)
        var seq = [Block]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterTypeBlock.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterSequenceTypeItem: FfiConverterRustBuffer {
    typealias SwiftType = [Item]

    public static func write(_ value: [Item], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for item in value {
            FfiConverterTypeItem.write(item, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Item] {
        let len: Int32 = try readInt(&buf)
        var seq = [Item]()
        seq.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            try seq.append(FfiConverterTypeItem.read(from: &buf))
        }
        return seq
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterDictionaryStringDictionaryTypeGroupedQuantityKeyTypeValue: FfiConverterRustBuffer {
    public static func write(_ value: [String: [GroupedQuantityKey: Value]], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for (key, value) in value {
            FfiConverterString.write(key, into: &buf)
            FfiConverterDictionaryTypeGroupedQuantityKeyTypeValue.write(value, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String: [GroupedQuantityKey: Value]] {
        let len: Int32 = try readInt(&buf)
        var dict = [String: [GroupedQuantityKey: Value]]()
        dict.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            let key = try FfiConverterString.read(from: &buf)
            let value = try FfiConverterDictionaryTypeGroupedQuantityKeyTypeValue.read(from: &buf)
            dict[key] = value
        }
        return dict
    }
}

#if swift(>=5.8)
    @_documentation(visibility: private)
#endif
private struct FfiConverterDictionaryTypeGroupedQuantityKeyTypeValue: FfiConverterRustBuffer {
    public static func write(_ value: [GroupedQuantityKey: Value], into buf: inout [UInt8]) {
        let len = Int32(value.count)
        writeInt(&buf, len)
        for (key, value) in value {
            FfiConverterTypeGroupedQuantityKey.write(key, into: &buf)
            FfiConverterTypeValue.write(value, into: &buf)
        }
    }

    public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [GroupedQuantityKey: Value] {
        let len: Int32 = try readInt(&buf)
        var dict = [GroupedQuantityKey: Value]()
        dict.reserveCapacity(Int(len))
        for _ in 0 ..< len {
            let key = try FfiConverterTypeGroupedQuantityKey.read(from: &buf)
            let value = try FfiConverterTypeValue.read(from: &buf)
            dict[key] = value
        }
        return dict
    }
}

/**
 * Combines a list of ingredients, grouping by name and summing quantities
 *
 * # Arguments
 * * `ingredients` - List of ingredients to combine
 *
 * # Returns
 * A map of ingredient names to their combined quantities
 */
public func combineIngredients(ingredients: [Ingredient]) -> [String: [GroupedQuantityKey: Value]] {
    return try! FfiConverterDictionaryStringDictionaryTypeGroupedQuantityKeyTypeValue.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_combine_ingredients(
            FfiConverterSequenceTypeIngredient.lower(ingredients), $0
        )
    })
}

/**
 * Combines selected ingredients by their indices
 *
 * # Arguments
 * * `ingredients` - Full list of ingredients
 * * `indices` - Indices of ingredients to combine
 *
 * # Returns
 * A map of ingredient names to their combined quantities
 */
public func combineIngredientsSelected(ingredients: [Ingredient], indices: [UInt32]) -> [String: [GroupedQuantityKey: Value]] {
    return try! FfiConverterDictionaryStringDictionaryTypeGroupedQuantityKeyTypeValue.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_combine_ingredients_selected(
            FfiConverterSequenceTypeIngredient.lower(ingredients),
            FfiConverterSequenceUInt32.lower(indices), $0
        )
    })
}

/**
 * Dereferences a component reference to get the actual component
 *
 * # Arguments
 * * `recipe` - The recipe containing the components
 * * `item` - The item reference (IngredientRef, CookwareRef, TimerRef, or Text)
 *
 * # Returns
 * The actual component (Ingredient, Cookware, Timer, or Text)
 */
public func derefComponent(recipe: CooklangRecipe, item: Item) -> Component {
    return try! FfiConverterTypeComponent.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_deref_component(
            FfiConverterTypeCooklangRecipe.lower(recipe),
            FfiConverterTypeItem.lower(item), $0
        )
    })
}

/**
 * Gets cookware by its index
 *
 * # Arguments
 * * `recipe` - The recipe containing the cookware
 * * `index` - The index of the cookware
 *
 * # Returns
 * The cookware at the specified index
 */
public func derefCookware(recipe: CooklangRecipe, index: UInt32) -> Cookware {
    return try! FfiConverterTypeCookware.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_deref_cookware(
            FfiConverterTypeCooklangRecipe.lower(recipe),
            FfiConverterUInt32.lower(index), $0
        )
    })
}

/**
 * Gets an ingredient by its index
 *
 * # Arguments
 * * `recipe` - The recipe containing the ingredients
 * * `index` - The index of the ingredient
 *
 * # Returns
 * The ingredient at the specified index
 */
public func derefIngredient(recipe: CooklangRecipe, index: UInt32) -> Ingredient {
    return try! FfiConverterTypeIngredient.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_deref_ingredient(
            FfiConverterTypeCooklangRecipe.lower(recipe),
            FfiConverterUInt32.lower(index), $0
        )
    })
}

/**
 * Gets a timer by its index
 *
 * # Arguments
 * * `recipe` - The recipe containing the timers
 * * `index` - The index of the timer
 *
 * # Returns
 * The timer at the specified index
 */
public func derefTimer(recipe: CooklangRecipe, index: UInt32) -> Timer {
    return try! FfiConverterTypeTimer.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_deref_timer(
            FfiConverterTypeCooklangRecipe.lower(recipe),
            FfiConverterUInt32.lower(index), $0
        )
    })
}

/**
 * Formats an Amount to a display string with units
 *
 * Combines formatted quantity with units (e.g., "2/3 cups", "1 1/2 tsp")
 *
 * # Arguments
 * * `amount` - The amount to format
 *
 * # Returns
 * Formatted string with quantity and units
 */
public func formatAmount(amount: Amount) -> String {
    return try! FfiConverterString.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_format_amount(
            FfiConverterTypeAmount.lower(amount), $0
        )
    })
}

/**
 * Formats a Value to a display string with proper fraction handling
 *
 * Converts decimals to fractions where appropriate (e.g., 0.666667 -> "2/3")
 * Handles floating point precision issues from scaling (e.g., 0.89999999 -> "0.9")
 *
 * # Arguments
 * * `value` - The value to format
 *
 * # Returns
 * Formatted string or None for Empty values
 */
public func formatValue(value: Value) -> String? {
    return try! FfiConverterOptionString.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_format_value(
            FfiConverterTypeValue.lower(value), $0
        )
    })
}

/**
 * Gets the author information from recipe metadata
 *
 * # Arguments
 * * `recipe` - The recipe to get author from
 *
 * # Returns
 * Author name and optional URL
 */
public func metadataAuthor(recipe: CooklangRecipe) -> NameAndUrl? {
    return try! FfiConverterOptionTypeNameAndUrl.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_author(
            FfiConverterTypeCooklangRecipe.lower(recipe), $0
        )
    })
}

/**
 * Gets all non-standard (custom) metadata keys
 *
 * # Arguments
 * * `recipe` - The recipe containing metadata
 *
 * # Returns
 * List of custom metadata keys that are not part of the Cooklang standard
 */
public func metadataCustomKeys(recipe: CooklangRecipe) -> [String] {
    return try! FfiConverterSequenceString.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_custom_keys(
            FfiConverterTypeCooklangRecipe.lower(recipe), $0
        )
    })
}

/**
 * Gets the description from recipe metadata
 *
 * # Arguments
 * * `recipe` - The recipe to get the description from
 *
 * # Returns
 * The recipe description if present
 */
public func metadataDescription(recipe: CooklangRecipe) -> String? {
    return try! FfiConverterOptionString.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_description(
            FfiConverterTypeCooklangRecipe.lower(recipe), $0
        )
    })
}

/**
 * Gets a custom metadata value by key
 *
 * # Arguments
 * * `recipe` - The recipe containing metadata
 * * `key` - The metadata key to retrieve
 *
 * # Returns
 * The metadata value if present
 */
public func metadataGet(recipe: CooklangRecipe, key: String) -> String? {
    return try! FfiConverterOptionString.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_get(
            FfiConverterTypeCooklangRecipe.lower(recipe),
            FfiConverterString.lower(key), $0
        )
    })
}

/**
 * Gets a standard metadata value using the StdKey enum
 *
 * # Arguments
 * * `recipe` - The recipe containing metadata
 * * `key` - The standard metadata key
 *
 * # Returns
 * The metadata value if present
 */
public func metadataGetStd(recipe: CooklangRecipe, key: StdKey) -> String? {
    return try! FfiConverterOptionString.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_get_std(
            FfiConverterTypeCooklangRecipe.lower(recipe),
            FfiConverterTypeStdKey.lower(key), $0
        )
    })
}

/**
 * Gets the servings from recipe metadata
 *
 * # Arguments
 * * `recipe` - The recipe to get servings from
 *
 * # Returns
 * Servings as either a number (e.g., 4) or text (e.g., "2-3 portions")
 */
public func metadataServings(recipe: CooklangRecipe) -> Servings? {
    return try! FfiConverterOptionTypeServings.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_servings(
            FfiConverterTypeCooklangRecipe.lower(recipe), $0
        )
    })
}

/**
 * Gets the source information from recipe metadata
 *
 * # Arguments
 * * `recipe` - The recipe to get source from
 *
 * # Returns
 * Source name and optional URL
 */
public func metadataSource(recipe: CooklangRecipe) -> NameAndUrl? {
    return try! FfiConverterOptionTypeNameAndUrl.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_source(
            FfiConverterTypeCooklangRecipe.lower(recipe), $0
        )
    })
}

/**
 * Gets tags from recipe metadata
 *
 * # Arguments
 * * `recipe` - The recipe to get tags from
 *
 * # Returns
 * A list of tags if present
 */
public func metadataTags(recipe: CooklangRecipe) -> [String]? {
    return try! FfiConverterOptionSequenceString.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_tags(
            FfiConverterTypeCooklangRecipe.lower(recipe), $0
        )
    })
}

/**
 * Gets the time information from recipe metadata
 *
 * # Arguments
 * * `recipe` - The recipe to get time from
 *
 * # Returns
 * Total time or separate prep/cook times in minutes
 */
public func metadataTime(recipe: CooklangRecipe) -> RecipeTime? {
    return try! FfiConverterOptionTypeRecipeTime.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_time(
            FfiConverterTypeCooklangRecipe.lower(recipe), $0
        )
    })
}

/**
 * Gets the title from recipe metadata
 *
 * # Arguments
 * * `recipe` - The recipe to get the title from
 *
 * # Returns
 * The recipe title if present
 */
public func metadataTitle(recipe: CooklangRecipe) -> String? {
    return try! FfiConverterOptionString.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_metadata_title(
            FfiConverterTypeCooklangRecipe.lower(recipe), $0
        )
    })
}

/**
 * Parses an aisle configuration for shopping list organization
 *
 * # Arguments
 * * `input` - The aisle configuration text
 *
 * # Returns
 * Parsed aisle configuration with categories and ingredient mappings
 */
public func parseAisleConfig(input: String) -> AisleConf {
    return try! FfiConverterTypeAisleConf.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_parse_aisle_config(
            FfiConverterString.lower(input), $0
        )
    })
}

/**
 * Parses a Cooklang recipe from text and applies a scaling factor
 *
 * # Arguments
 * * `input` - The raw recipe text in Cooklang format
 * * `scaling_factor` - Factor to scale ingredient quantities (1.0 for no scaling)
 *
 * # Returns
 * A parsed recipe object with metadata, sections, ingredients, cookware and timers
 */
public func parseRecipe(input: String, scalingFactor: Double) -> CooklangRecipe {
    return try! FfiConverterTypeCooklangRecipe.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_parse_recipe(
            FfiConverterString.lower(input),
            FfiConverterDouble.lower(scalingFactor), $0
        )
    })
}

/**
 * Parses a string into a Value
 *
 * Supports fractions (e.g., "1/2" -> 0.5), mixed numbers (e.g., "1 1/2" -> 1.5),
 * ranges (e.g., "1/2 - 3/4" -> Range{0.5, 0.75}), or falls back to text
 *
 * # Arguments
 * * `s` - The string to parse
 *
 * # Returns
 * Parsed Value (Number, Range, or Text)
 */
public func parseValue(s: String) -> Value {
    return try! FfiConverterTypeValue.lift(try! rustCall {
        uniffi_cooklang_bindings_fn_func_parse_value(
            FfiConverterString.lower(s), $0
        )
    })
}

private enum InitializationResult {
    case ok
    case contractVersionMismatch
    case apiChecksumMismatch
}

// Use a global variable to perform the versioning checks. Swift ensures that
// the code inside is only computed once.
private var initializationResult: InitializationResult = {
    // Get the bindings contract version from our ComponentInterface
    let bindings_contract_version = 26
    // Get the scaffolding contract version by calling the into the dylib
    let scaffolding_contract_version = ffi_cooklang_bindings_uniffi_contract_version()
    if bindings_contract_version != scaffolding_contract_version {
        return InitializationResult.contractVersionMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_combine_ingredients() != 36610 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_combine_ingredients_selected() != 40919 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_deref_component() != 34036 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_deref_cookware() != 554 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_deref_ingredient() != 19669 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_deref_timer() != 59309 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_format_amount() != 64895 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_format_value() != 29360 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_author() != 27104 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_custom_keys() != 26863 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_description() != 22848 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_get() != 30261 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_get_std() != 65428 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_servings() != 62006 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_source() != 51247 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_tags() != 63258 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_time() != 27261 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_metadata_title() != 16632 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_parse_aisle_config() != 10549 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_parse_recipe() != 26150 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_func_parse_value() != 41886 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_method_aisleconf_category_for() != 45672 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_method_cooklangrecipe_cookware() != 42673 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_method_cooklangrecipe_ingredients() != 36256 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_method_cooklangrecipe_sections() != 55375 {
        return InitializationResult.apiChecksumMismatch
    }
    if uniffi_cooklang_bindings_checksum_method_cooklangrecipe_timers() != 63040 {
        return InitializationResult.apiChecksumMismatch
    }

    return InitializationResult.ok
}()

private func uniffiEnsureInitialized() {
    switch initializationResult {
    case .ok:
        break
    case .contractVersionMismatch:
        fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project")
    case .apiChecksumMismatch:
        fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
    }
}

// swiftlint:enable all
