From 6ff0714314d59e12ea1a7f1eec109d6af8ae9f87 Mon Sep 17 00:00:00 2001 From: ken-morel Date: Wed, 9 Sep 2026 12:29:21 +0530 Subject: [PATCH 1/4] Refactor --- .env.example | 5 - .flutter-plugins-dependencies | 1 - ANTIGRAVITY_BOOKBRIDGE_BRIEF_v2.md | 464 ------------------ CHANGELOG.md | 137 ------ GEMINI.md | 89 ---- README.md | 247 ---------- .gitignore => app/.gitignore | 0 .metadata => app/.metadata | 0 app/README.md | 247 ++++++++++ .../analysis_options.yaml | 0 {android => app/android}/.gitignore | 0 {android => app/android}/app/build.gradle.kts | 0 .../android}/app/google-services.json | 0 .../app/src/debug/AndroidManifest.xml | 0 .../android}/app/src/main/AndroidManifest.xml | 0 .../com/example/book_bridge/MainActivity.kt | 0 .../drawable-hdpi/ic_launcher_foreground.png | Bin .../drawable-mdpi/ic_launcher_foreground.png | Bin .../res/drawable-v21/launch_background.xml | 0 .../drawable-xhdpi/ic_launcher_foreground.png | Bin .../ic_launcher_foreground.png | Bin .../ic_launcher_foreground.png | Bin .../main/res/drawable/launch_background.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../app/src/main/res/values-night/styles.xml | 0 .../app/src/main/res/values/colors.xml | 0 .../app/src/main/res/values/styles.xml | 0 .../app/src/profile/AndroidManifest.xml | 0 {android => app/android}/build.gradle.kts | 0 {android => app/android}/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 {android => app/android}/settings.gradle.kts | 0 ...tigravity_Prompt_BookBridge_Rust_Phase1.md | 0 ...tigravity_Prompt_BookBridge_Rust_Phase2.md | 0 .../BookBridge_v2_Implementation_Plan.md | 0 {assets => app/assets}/Founder.jpg | Bin {assets => app/assets}/app_icon.png | Bin {assets => app/assets}/flow_diagram.png | Bin {assets => app/assets}/logo.png | Bin .../assets}/sreenshots/screenshot1.png | Bin .../assets}/sreenshots/screenshot2.png | Bin .../assets}/sreenshots/screenshot3.png | Bin firebase.json => app/firebase.json | 0 {ios => app/ios}/.gitignore | 0 .../ios}/Flutter/AppFrameworkInfo.plist | 0 {ios => app/ios}/Flutter/Debug.xcconfig | 0 {ios => app/ios}/Flutter/Release.xcconfig | 0 .../ios}/Runner.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 {ios => app/ios}/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-50x50@1x.png | Bin .../AppIcon.appiconset/Icon-App-50x50@2x.png | Bin .../AppIcon.appiconset/Icon-App-57x57@1x.png | Bin .../AppIcon.appiconset/Icon-App-57x57@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-72x72@1x.png | Bin .../AppIcon.appiconset/Icon-App-72x72@2x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios}/Runner/Base.lproj/Main.storyboard | 0 {ios => app/ios}/Runner/Info.plist | 0 .../ios}/Runner/Runner-Bridging-Header.h | 0 .../ios}/RunnerTests/RunnerTests.swift | 0 {lib => app/lib}/config/app_config.dart | 0 {lib => app/lib}/config/router.dart | 0 .../lib}/core/constants/categories.dart | 0 {lib => app/lib}/core/error/exceptions.dart | 0 {lib => app/lib}/core/error/failures.dart | 0 .../lib}/core/local_db/local_database.dart | 0 .../viewmodels/theme_viewmodel.dart | 0 .../widgets/notification_icon.dart | 0 .../presentation/widgets/offline_banner.dart | 0 .../widgets/scaffold_with_navbar.dart | 0 {lib => app/lib}/core/theme/app_theme.dart | 0 {lib => app/lib}/core/usecases/usecase.dart | 0 .../supabase_auth_data_source.dart | 0 .../features/auth/data/models/user_model.dart | 0 .../repositories/auth_repository_impl.dart | 0 .../features/auth/domain/entities/user.dart | 0 .../domain/repositories/auth_repository.dart | 0 .../usecases/get_current_user_usecase.dart | 0 .../send_password_reset_email_usecase.dart | 0 .../auth/domain/usecases/sign_in_usecase.dart | 0 .../usecases/sign_in_with_google_usecase.dart | 0 .../domain/usecases/sign_out_usecase.dart | 0 .../auth/domain/usecases/sign_up_usecase.dart | 0 .../domain/usecases/update_user_usecase.dart | 0 .../screens/complete_profile_screen.dart | 0 .../screens/edit_profile_screen.dart | 0 .../presentation/screens/sign_in_screen.dart | 0 .../presentation/screens/sign_up_screen.dart | 0 .../presentation/screens/terms_screen.dart | 0 .../viewmodels/auth_viewmodel.dart | 0 .../widgets/marketplace_agreement_sheet.dart | 0 .../supabase_chat_data_source.dart | 0 .../chat/data/models/message_model.dart | 0 .../repositories/chat_repository_impl.dart | 0 .../chat/domain/entities/conversation.dart | 0 .../chat/domain/entities/message.dart | 0 .../domain/repositories/chat_repository.dart | 0 .../screens/chat_list_screen.dart | 0 .../presentation/screens/chat_screen.dart | 0 .../viewmodels/chat_viewmodel.dart | 0 .../supabase_favorites_data_source.dart | 0 .../favorites/data/models/favorite_model.dart | 0 .../favorites_repository_impl.dart | 0 .../favorites/domain/entities/favorite.dart | 0 .../repositories/favorites_repository.dart | 0 .../usecases/get_favorites_usecase.dart | 0 .../domain/usecases/is_favorite_usecase.dart | 0 .../usecases/toggle_favorite_usecase.dart | 0 .../screens/favorites_screen.dart | 0 .../viewmodels/favorites_viewmodel.dart | 0 .../widgets/pulse_heart_icon.dart | 0 .../widgets/skeleton_listing_card.dart | 0 .../supabase_impact_data_source.dart | 0 .../data/models/platform_stats_model.dart | 0 .../repositories/impact_repository_impl.dart | 0 .../domain/entities/platform_stats.dart | 0 .../repositories/impact_repository.dart | 0 .../usecases/get_platform_stats_usecase.dart | 0 .../presentation/widgets/count_up_text.dart | 0 .../widgets/impact_stats_widget.dart | 0 .../local_listings_datasource.dart | 0 .../supabase_listings_data_source.dart | 0 .../supabase_storage_data_source.dart | 0 .../listings/data/models/listing_model.dart | 0 .../repositories/listing_repository_impl.dart | 0 .../domain/entities/book_condition.dart | 0 .../listings/domain/entities/category.dart | 0 .../listings/domain/entities/listing.dart | 0 .../repositories/listing_repository.dart | 0 .../usecases/create_listing_usecase.dart | 0 .../usecases/delete_listing_usecase.dart | 0 .../usecases/get_listing_details_usecase.dart | 0 .../domain/usecases/get_listings_usecase.dart | 0 .../usecases/get_user_listings_usecase.dart | 0 .../usecases/search_listings_usecase.dart | 0 .../usecases/update_listing_usecase.dart | 0 .../presentation/screens/about_screen.dart | 0 .../screens/categories_screen.dart | 0 .../screens/contact_us_screen.dart | 0 .../presentation/screens/faq_screen.dart | 0 .../presentation/screens/feedback_screen.dart | 0 .../presentation/screens/home_screen.dart | 0 .../screens/listing_details_screen.dart | 0 .../presentation/screens/my_books_screen.dart | 0 .../screens/privacy_policy_screen.dart | 0 .../presentation/screens/profile_screen.dart | 0 .../presentation/screens/search_screen.dart | 0 .../presentation/screens/sell_screen.dart | 0 .../screens/seller_profile_screen.dart | 0 .../viewmodels/home_viewmodel.dart | 0 .../viewmodels/listing_details_viewmodel.dart | 0 .../viewmodels/locale_viewmodel.dart | 0 .../viewmodels/location_viewmodel.dart | 0 .../viewmodels/profile_viewmodel.dart | 0 .../viewmodels/search_viewmodel.dart | 0 .../viewmodels/sell_viewmodel.dart | 0 .../viewmodels/seller_profile_viewmodel.dart | 0 .../presentation/widgets/listing_card.dart | 0 .../supabase_notifications_data_source.dart | 0 .../data/models/notification_model.dart | 0 .../notifications_repository_impl.dart | 0 .../services/push_notification_service.dart | 0 .../domain/entities/notification.dart | 0 .../notifications_repository.dart | 0 .../screens/notifications_screen.dart | 0 .../viewmodels/notifications_viewmodel.dart | 0 .../data/datasources/fapshi_data_source.dart | 0 .../repositories/payment_repository_impl.dart | 0 .../repositories/payment_repository.dart | 0 .../usecases/collect_payment_usecase.dart | 0 .../usecases/get_payment_status_usecase.dart | 0 .../viewmodels/payment_viewmodel.dart | 0 .../widgets/payment_bottom_sheet.dart | 0 .../supabase_reviews_data_source.dart | 0 .../repositories/review_repository_impl.dart | 0 .../domain/entities/review_entity.dart | 0 .../repositories/review_repository.dart | 0 .../usecases/create_review_usecase.dart | 0 .../usecases/get_user_reviews_usecase.dart | 0 .../domain/usecases/has_reviewed_usecase.dart | 0 .../viewmodels/review_viewmodel.dart | 0 .../presentation/widgets/review_dialog.dart | 0 .../widgets/seller_rating_badge.dart | 0 .../widgets/seller_trust_card.dart | 0 .../widgets/star_rating_display.dart | 0 .../datasources/safety_remote_datasource.dart | 0 .../safety/data/models/campus_zone_model.dart | 0 .../repositories/safety_repository_impl.dart | 0 .../safety/domain/entities/campus_zone.dart | 0 .../repositories/safety_repository.dart | 0 .../usecases/get_campus_zones_usecase.dart | 0 .../screens/safety_guidelines_screen.dart | 0 .../viewmodels/safety_viewmodel.dart | 0 .../widgets/meetup_tips_card.dart | 0 .../supabase_transactions_data_source.dart | 0 .../transaction_repository_impl.dart | 0 .../domain/entities/transaction_entity.dart | 0 .../repositories/transaction_repository.dart | 0 ...t_transaction_by_external_ref_usecase.dart | 0 .../get_user_transactions_usecase.dart | 0 .../screens/transaction_history_screen.dart | 0 .../transaction_history_viewmodel.dart | 0 {lib => app/lib}/firebase_options.dart | 0 {lib => app/lib}/injection_container.dart | 0 {lib => app/lib}/l10n/app_en.arb | 0 {lib => app/lib}/l10n/app_fr.arb | 0 {lib => app/lib}/l10n/app_localizations.dart | 0 .../lib}/l10n/app_localizations_en.dart | 0 .../lib}/l10n/app_localizations_fr.dart | 0 {lib => app/lib}/main.dart | 0 {linux => app/linux}/.gitignore | 0 {linux => app/linux}/CMakeLists.txt | 0 {linux => app/linux}/flutter/CMakeLists.txt | 0 .../flutter/generated_plugin_registrant.cc | 0 .../flutter/generated_plugin_registrant.h | 0 .../linux}/flutter/generated_plugins.cmake | 0 {linux => app/linux}/runner/CMakeLists.txt | 0 {linux => app/linux}/runner/main.cc | 0 {linux => app/linux}/runner/my_application.cc | 0 {linux => app/linux}/runner/my_application.h | 0 {macos => app/macos}/.gitignore | 0 .../macos}/Flutter/Flutter-Debug.xcconfig | 0 .../macos}/Flutter/Flutter-Release.xcconfig | 0 .../Flutter/GeneratedPluginRegistrant.swift | 0 .../macos}/Runner.xcodeproj/project.pbxproj | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 {macos => app/macos}/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/app_icon_1024.png | Bin .../AppIcon.appiconset/app_icon_128.png | Bin .../AppIcon.appiconset/app_icon_16.png | Bin .../AppIcon.appiconset/app_icon_256.png | Bin .../AppIcon.appiconset/app_icon_32.png | Bin .../AppIcon.appiconset/app_icon_512.png | Bin .../AppIcon.appiconset/app_icon_64.png | Bin .../macos}/Runner/Base.lproj/MainMenu.xib | 0 .../macos}/Runner/Configs/AppInfo.xcconfig | 0 .../macos}/Runner/Configs/Debug.xcconfig | 0 .../macos}/Runner/Configs/Release.xcconfig | 0 .../macos}/Runner/Configs/Warnings.xcconfig | 0 .../macos}/Runner/DebugProfile.entitlements | 0 {macos => app/macos}/Runner/Info.plist | 0 .../macos}/Runner/MainFlutterWindow.swift | 0 .../macos}/Runner/Release.entitlements | 0 .../macos}/RunnerTests/RunnerTests.swift | 0 pubspec.yaml => app/pubspec.yaml | 0 {test => app/test}/.gitkeep | 0 .../viewmodels/chat_viewmodel_test.dart | 0 .../screens/seller_profile_screen_test.dart | 0 .../seller_profile_viewmodel_test.dart | 0 {web => app/web}/favicon.png | Bin {web => app/web}/icons/Icon-192.png | Bin {web => app/web}/icons/Icon-512.png | Bin {web => app/web}/icons/Icon-maskable-192.png | Bin {web => app/web}/icons/Icon-maskable-512.png | Bin {web => app/web}/index.html | 0 {web => app/web}/manifest.json | 0 {windows => app/windows}/.gitignore | 0 {windows => app/windows}/CMakeLists.txt | 0 .../windows}/flutter/CMakeLists.txt | 0 .../flutter/generated_plugin_registrant.cc | 0 .../flutter/generated_plugin_registrant.h | 0 .../windows}/flutter/generated_plugins.cmake | 0 .../windows}/runner/CMakeLists.txt | 0 {windows => app/windows}/runner/Runner.rc | 0 .../windows}/runner/flutter_window.cpp | 0 .../windows}/runner/flutter_window.h | 0 {windows => app/windows}/runner/main.cpp | 0 {windows => app/windows}/runner/resource.h | 0 .../windows}/runner/resources/app_icon.ico | Bin .../windows}/runner/runner.exe.manifest | 0 {windows => app/windows}/runner/utils.cpp | 0 {windows => app/windows}/runner/utils.h | 0 .../windows}/runner/win32_window.cpp | 0 .../windows}/runner/win32_window.h | 0 backend/Cargo.toml | 6 + backend/src/main.rs | 3 + bookbridge-rust-core/.env.example | 10 - bookbridge-rust-core/Cargo.toml | 21 - bookbridge-rust-core/src/auth.rs | 38 -- bookbridge-rust-core/src/config.rs | 35 -- bookbridge-rust-core/src/error.rs | 72 --- bookbridge-rust-core/src/fapshi.rs | 284 ----------- bookbridge-rust-core/src/lib.rs | 18 - bookbridge-rust-core/src/main.rs | 69 --- bookbridge-rust-core/src/routes/escrow.rs | 392 --------------- bookbridge-rust-core/src/routes/health.rs | 6 - bookbridge-rust-core/src/routes/mod.rs | 3 - bookbridge-rust-core/src/routes/webhook.rs | 372 -------------- bookbridge-rust-core/tests/auth_tests.rs | 56 --- bookbridge-rust-core/tests/escrow_tests.rs | 294 ----------- bookbridge-rust-core/tests/webhook_tests.rs | 235 --------- git_final_out.txt | 9 - git_log_final.txt | 39 -- git_log_now.txt | 11 - git_merge_push_log.txt | 2 - git_status_debug.txt | 25 - git_status_now.txt | 9 - supabase/favorites_migration.sql | 53 -- supabase/feedback_migration.sql | 20 - supabase/functions/fapshi-polling/index.ts | 148 ------ supabase/functions/process-escrow/index.ts | 382 -------------- .../20260602130000_escrow_payment_flow.sql | 98 ---- ...24500_update_transactions_status_check.sql | 6 - ...60611180000_fintech_architecture_fixes.sql | 90 ---- test.txt | 1 - {landingPage => web}/.gitignore | 0 {landingPage => web}/.npmrc | 0 {landingPage => web}/check_db.py | 0 {landingPage => web}/check_supabase_fast.py | 0 {landingPage => web}/check_tx.js | 0 {landingPage => web}/jsconfig.json | 0 {landingPage => web}/package-lock.json | 0 {landingPage => web}/package.json | 0 {landingPage => web}/src/app.css | 0 {landingPage => web}/src/app.d.ts | 0 {landingPage => web}/src/app.html | 0 .../src/lib/assets/Founder.jpg | Bin .../src/lib/assets/favicon.svg | 0 {landingPage => web}/src/lib/assets/logo.png | Bin .../src/lib/assets/screenshot.png | Bin .../src/lib/components/AppShowcase.svelte | 0 .../src/lib/components/Features.svelte | 0 .../src/lib/components/Footer.svelte | 0 .../src/lib/components/Founder.svelte | 0 .../src/lib/components/Hero.svelte | 0 .../src/lib/components/HowItWorks.svelte | 0 .../src/lib/components/Navbar.svelte | 0 .../src/lib/components/TrustBar.svelte | 0 {landingPage => web}/src/lib/index.js | 0 {landingPage => web}/src/lib/links.js | 0 {landingPage => web}/src/lib/theme.svelte.js | 0 .../src/routes/+layout.svelte | 0 {landingPage => web}/src/routes/+page.svelte | 0 .../src/routes/api/webhooks/campay/+server.js | 0 .../api/webhooks/fapshi-payouts/+server.js | 0 .../src/routes/api/webhooks/fapshi/+server.js | 0 {landingPage => web}/static/favicon.png | Bin {landingPage => web}/static/robots.txt | 0 {landingPage => web}/svelte.config.js | 0 {landingPage => web}/vite.config.js | 0 377 files changed, 256 insertions(+), 3741 deletions(-) delete mode 100644 .env.example delete mode 100644 .flutter-plugins-dependencies delete mode 100644 ANTIGRAVITY_BOOKBRIDGE_BRIEF_v2.md delete mode 100644 CHANGELOG.md delete mode 100644 GEMINI.md rename .gitignore => app/.gitignore (100%) rename .metadata => app/.metadata (100%) create mode 100644 app/README.md rename analysis_options.yaml => app/analysis_options.yaml (100%) rename {android => app/android}/.gitignore (100%) rename {android => app/android}/app/build.gradle.kts (100%) rename {android => app/android}/app/google-services.json (100%) rename {android => app/android}/app/src/debug/AndroidManifest.xml (100%) rename {android => app/android}/app/src/main/AndroidManifest.xml (100%) rename {android => app/android}/app/src/main/kotlin/com/example/book_bridge/MainActivity.kt (100%) rename {android => app/android}/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png (100%) rename {android => app/android}/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png (100%) rename {android => app/android}/app/src/main/res/drawable-v21/launch_background.xml (100%) rename {android => app/android}/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png (100%) rename {android => app/android}/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png (100%) rename {android => app/android}/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png (100%) rename {android => app/android}/app/src/main/res/drawable/launch_background.xml (100%) rename {android => app/android}/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (100%) rename {android => app/android}/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {android => app/android}/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {android => app/android}/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {android => app/android}/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {android => app/android}/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {android => app/android}/app/src/main/res/values-night/styles.xml (100%) rename {android => app/android}/app/src/main/res/values/colors.xml (100%) rename {android => app/android}/app/src/main/res/values/styles.xml (100%) rename {android => app/android}/app/src/profile/AndroidManifest.xml (100%) rename {android => app/android}/build.gradle.kts (100%) rename {android => app/android}/gradle.properties (100%) rename {android => app/android}/gradle/wrapper/gradle-wrapper.properties (100%) rename {android => app/android}/settings.gradle.kts (100%) rename {assets => app/assets}/Antigravity_Prompt_BookBridge_Rust_Phase1.md (100%) rename {assets => app/assets}/Antigravity_Prompt_BookBridge_Rust_Phase2.md (100%) rename {assets => app/assets}/BookBridge_v2_Implementation_Plan.md (100%) rename {assets => app/assets}/Founder.jpg (100%) rename {assets => app/assets}/app_icon.png (100%) rename {assets => app/assets}/flow_diagram.png (100%) rename {assets => app/assets}/logo.png (100%) rename {assets => app/assets}/sreenshots/screenshot1.png (100%) rename {assets => app/assets}/sreenshots/screenshot2.png (100%) rename {assets => app/assets}/sreenshots/screenshot3.png (100%) rename firebase.json => app/firebase.json (100%) rename {ios => app/ios}/.gitignore (100%) rename {ios => app/ios}/Flutter/AppFrameworkInfo.plist (100%) rename {ios => app/ios}/Flutter/Debug.xcconfig (100%) rename {ios => app/ios}/Flutter/Release.xcconfig (100%) rename {ios => app/ios}/Runner.xcodeproj/project.pbxproj (100%) rename {ios => app/ios}/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename {ios => app/ios}/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {ios => app/ios}/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {ios => app/ios}/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename {ios => app/ios}/Runner.xcworkspace/contents.xcworkspacedata (100%) rename {ios => app/ios}/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {ios => app/ios}/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {ios => app/ios}/Runner/AppDelegate.swift (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename {ios => app/ios}/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename {ios => app/ios}/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename {ios => app/ios}/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename {ios => app/ios}/Runner/Base.lproj/Main.storyboard (100%) rename {ios => app/ios}/Runner/Info.plist (100%) rename {ios => app/ios}/Runner/Runner-Bridging-Header.h (100%) rename {ios => app/ios}/RunnerTests/RunnerTests.swift (100%) rename {lib => app/lib}/config/app_config.dart (100%) rename {lib => app/lib}/config/router.dart (100%) rename {lib => app/lib}/core/constants/categories.dart (100%) rename {lib => app/lib}/core/error/exceptions.dart (100%) rename {lib => app/lib}/core/error/failures.dart (100%) rename {lib => app/lib}/core/local_db/local_database.dart (100%) rename {lib => app/lib}/core/presentation/viewmodels/theme_viewmodel.dart (100%) rename {lib => app/lib}/core/presentation/widgets/notification_icon.dart (100%) rename {lib => app/lib}/core/presentation/widgets/offline_banner.dart (100%) rename {lib => app/lib}/core/presentation/widgets/scaffold_with_navbar.dart (100%) rename {lib => app/lib}/core/theme/app_theme.dart (100%) rename {lib => app/lib}/core/usecases/usecase.dart (100%) rename {lib => app/lib}/features/auth/data/datasources/supabase_auth_data_source.dart (100%) rename {lib => app/lib}/features/auth/data/models/user_model.dart (100%) rename {lib => app/lib}/features/auth/data/repositories/auth_repository_impl.dart (100%) rename {lib => app/lib}/features/auth/domain/entities/user.dart (100%) rename {lib => app/lib}/features/auth/domain/repositories/auth_repository.dart (100%) rename {lib => app/lib}/features/auth/domain/usecases/get_current_user_usecase.dart (100%) rename {lib => app/lib}/features/auth/domain/usecases/send_password_reset_email_usecase.dart (100%) rename {lib => app/lib}/features/auth/domain/usecases/sign_in_usecase.dart (100%) rename {lib => app/lib}/features/auth/domain/usecases/sign_in_with_google_usecase.dart (100%) rename {lib => app/lib}/features/auth/domain/usecases/sign_out_usecase.dart (100%) rename {lib => app/lib}/features/auth/domain/usecases/sign_up_usecase.dart (100%) rename {lib => app/lib}/features/auth/domain/usecases/update_user_usecase.dart (100%) rename {lib => app/lib}/features/auth/presentation/screens/complete_profile_screen.dart (100%) rename {lib => app/lib}/features/auth/presentation/screens/edit_profile_screen.dart (100%) rename {lib => app/lib}/features/auth/presentation/screens/sign_in_screen.dart (100%) rename {lib => app/lib}/features/auth/presentation/screens/sign_up_screen.dart (100%) rename {lib => app/lib}/features/auth/presentation/screens/terms_screen.dart (100%) rename {lib => app/lib}/features/auth/presentation/viewmodels/auth_viewmodel.dart (100%) rename {lib => app/lib}/features/auth/presentation/widgets/marketplace_agreement_sheet.dart (100%) rename {lib => app/lib}/features/chat/data/datasources/supabase_chat_data_source.dart (100%) rename {lib => app/lib}/features/chat/data/models/message_model.dart (100%) rename {lib => app/lib}/features/chat/data/repositories/chat_repository_impl.dart (100%) rename {lib => app/lib}/features/chat/domain/entities/conversation.dart (100%) rename {lib => app/lib}/features/chat/domain/entities/message.dart (100%) rename {lib => app/lib}/features/chat/domain/repositories/chat_repository.dart (100%) rename {lib => app/lib}/features/chat/presentation/screens/chat_list_screen.dart (100%) rename {lib => app/lib}/features/chat/presentation/screens/chat_screen.dart (100%) rename {lib => app/lib}/features/chat/presentation/viewmodels/chat_viewmodel.dart (100%) rename {lib => app/lib}/features/favorites/data/datasources/supabase_favorites_data_source.dart (100%) rename {lib => app/lib}/features/favorites/data/models/favorite_model.dart (100%) rename {lib => app/lib}/features/favorites/data/repositories/favorites_repository_impl.dart (100%) rename {lib => app/lib}/features/favorites/domain/entities/favorite.dart (100%) rename {lib => app/lib}/features/favorites/domain/repositories/favorites_repository.dart (100%) rename {lib => app/lib}/features/favorites/domain/usecases/get_favorites_usecase.dart (100%) rename {lib => app/lib}/features/favorites/domain/usecases/is_favorite_usecase.dart (100%) rename {lib => app/lib}/features/favorites/domain/usecases/toggle_favorite_usecase.dart (100%) rename {lib => app/lib}/features/favorites/presentation/screens/favorites_screen.dart (100%) rename {lib => app/lib}/features/favorites/presentation/viewmodels/favorites_viewmodel.dart (100%) rename {lib => app/lib}/features/favorites/presentation/widgets/pulse_heart_icon.dart (100%) rename {lib => app/lib}/features/favorites/presentation/widgets/skeleton_listing_card.dart (100%) rename {lib => app/lib}/features/impact/data/datasources/supabase_impact_data_source.dart (100%) rename {lib => app/lib}/features/impact/data/models/platform_stats_model.dart (100%) rename {lib => app/lib}/features/impact/data/repositories/impact_repository_impl.dart (100%) rename {lib => app/lib}/features/impact/domain/entities/platform_stats.dart (100%) rename {lib => app/lib}/features/impact/domain/repositories/impact_repository.dart (100%) rename {lib => app/lib}/features/impact/domain/usecases/get_platform_stats_usecase.dart (100%) rename {lib => app/lib}/features/impact/presentation/widgets/count_up_text.dart (100%) rename {lib => app/lib}/features/impact/presentation/widgets/impact_stats_widget.dart (100%) rename {lib => app/lib}/features/listings/data/datasources/local_listings_datasource.dart (100%) rename {lib => app/lib}/features/listings/data/datasources/supabase_listings_data_source.dart (100%) rename {lib => app/lib}/features/listings/data/datasources/supabase_storage_data_source.dart (100%) rename {lib => app/lib}/features/listings/data/models/listing_model.dart (100%) rename {lib => app/lib}/features/listings/data/repositories/listing_repository_impl.dart (100%) rename {lib => app/lib}/features/listings/domain/entities/book_condition.dart (100%) rename {lib => app/lib}/features/listings/domain/entities/category.dart (100%) rename {lib => app/lib}/features/listings/domain/entities/listing.dart (100%) rename {lib => app/lib}/features/listings/domain/repositories/listing_repository.dart (100%) rename {lib => app/lib}/features/listings/domain/usecases/create_listing_usecase.dart (100%) rename {lib => app/lib}/features/listings/domain/usecases/delete_listing_usecase.dart (100%) rename {lib => app/lib}/features/listings/domain/usecases/get_listing_details_usecase.dart (100%) rename {lib => app/lib}/features/listings/domain/usecases/get_listings_usecase.dart (100%) rename {lib => app/lib}/features/listings/domain/usecases/get_user_listings_usecase.dart (100%) rename {lib => app/lib}/features/listings/domain/usecases/search_listings_usecase.dart (100%) rename {lib => app/lib}/features/listings/domain/usecases/update_listing_usecase.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/about_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/categories_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/contact_us_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/faq_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/feedback_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/home_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/listing_details_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/my_books_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/privacy_policy_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/profile_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/search_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/sell_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/screens/seller_profile_screen.dart (100%) rename {lib => app/lib}/features/listings/presentation/viewmodels/home_viewmodel.dart (100%) rename {lib => app/lib}/features/listings/presentation/viewmodels/listing_details_viewmodel.dart (100%) rename {lib => app/lib}/features/listings/presentation/viewmodels/locale_viewmodel.dart (100%) rename {lib => app/lib}/features/listings/presentation/viewmodels/location_viewmodel.dart (100%) rename {lib => app/lib}/features/listings/presentation/viewmodels/profile_viewmodel.dart (100%) rename {lib => app/lib}/features/listings/presentation/viewmodels/search_viewmodel.dart (100%) rename {lib => app/lib}/features/listings/presentation/viewmodels/sell_viewmodel.dart (100%) rename {lib => app/lib}/features/listings/presentation/viewmodels/seller_profile_viewmodel.dart (100%) rename {lib => app/lib}/features/listings/presentation/widgets/listing_card.dart (100%) rename {lib => app/lib}/features/notifications/data/datasources/supabase_notifications_data_source.dart (100%) rename {lib => app/lib}/features/notifications/data/models/notification_model.dart (100%) rename {lib => app/lib}/features/notifications/data/repositories/notifications_repository_impl.dart (100%) rename {lib => app/lib}/features/notifications/data/services/push_notification_service.dart (100%) rename {lib => app/lib}/features/notifications/domain/entities/notification.dart (100%) rename {lib => app/lib}/features/notifications/domain/repositories/notifications_repository.dart (100%) rename {lib => app/lib}/features/notifications/presentation/screens/notifications_screen.dart (100%) rename {lib => app/lib}/features/notifications/presentation/viewmodels/notifications_viewmodel.dart (100%) rename {lib => app/lib}/features/payments/data/datasources/fapshi_data_source.dart (100%) rename {lib => app/lib}/features/payments/data/repositories/payment_repository_impl.dart (100%) rename {lib => app/lib}/features/payments/domain/repositories/payment_repository.dart (100%) rename {lib => app/lib}/features/payments/domain/usecases/collect_payment_usecase.dart (100%) rename {lib => app/lib}/features/payments/domain/usecases/get_payment_status_usecase.dart (100%) rename {lib => app/lib}/features/payments/presentation/viewmodels/payment_viewmodel.dart (100%) rename {lib => app/lib}/features/payments/presentation/widgets/payment_bottom_sheet.dart (100%) rename {lib => app/lib}/features/reviews/data/datasources/supabase_reviews_data_source.dart (100%) rename {lib => app/lib}/features/reviews/data/repositories/review_repository_impl.dart (100%) rename {lib => app/lib}/features/reviews/domain/entities/review_entity.dart (100%) rename {lib => app/lib}/features/reviews/domain/repositories/review_repository.dart (100%) rename {lib => app/lib}/features/reviews/domain/usecases/create_review_usecase.dart (100%) rename {lib => app/lib}/features/reviews/domain/usecases/get_user_reviews_usecase.dart (100%) rename {lib => app/lib}/features/reviews/domain/usecases/has_reviewed_usecase.dart (100%) rename {lib => app/lib}/features/reviews/presentation/viewmodels/review_viewmodel.dart (100%) rename {lib => app/lib}/features/reviews/presentation/widgets/review_dialog.dart (100%) rename {lib => app/lib}/features/reviews/presentation/widgets/seller_rating_badge.dart (100%) rename {lib => app/lib}/features/reviews/presentation/widgets/seller_trust_card.dart (100%) rename {lib => app/lib}/features/reviews/presentation/widgets/star_rating_display.dart (100%) rename {lib => app/lib}/features/safety/data/datasources/safety_remote_datasource.dart (100%) rename {lib => app/lib}/features/safety/data/models/campus_zone_model.dart (100%) rename {lib => app/lib}/features/safety/data/repositories/safety_repository_impl.dart (100%) rename {lib => app/lib}/features/safety/domain/entities/campus_zone.dart (100%) rename {lib => app/lib}/features/safety/domain/repositories/safety_repository.dart (100%) rename {lib => app/lib}/features/safety/domain/usecases/get_campus_zones_usecase.dart (100%) rename {lib => app/lib}/features/safety/presentation/screens/safety_guidelines_screen.dart (100%) rename {lib => app/lib}/features/safety/presentation/viewmodels/safety_viewmodel.dart (100%) rename {lib => app/lib}/features/safety/presentation/widgets/meetup_tips_card.dart (100%) rename {lib => app/lib}/features/transactions/data/datasources/supabase_transactions_data_source.dart (100%) rename {lib => app/lib}/features/transactions/data/repositories/transaction_repository_impl.dart (100%) rename {lib => app/lib}/features/transactions/domain/entities/transaction_entity.dart (100%) rename {lib => app/lib}/features/transactions/domain/repositories/transaction_repository.dart (100%) rename {lib => app/lib}/features/transactions/domain/usecases/get_transaction_by_external_ref_usecase.dart (100%) rename {lib => app/lib}/features/transactions/domain/usecases/get_user_transactions_usecase.dart (100%) rename {lib => app/lib}/features/transactions/presentation/screens/transaction_history_screen.dart (100%) rename {lib => app/lib}/features/transactions/presentation/viewmodels/transaction_history_viewmodel.dart (100%) rename {lib => app/lib}/firebase_options.dart (100%) rename {lib => app/lib}/injection_container.dart (100%) rename {lib => app/lib}/l10n/app_en.arb (100%) rename {lib => app/lib}/l10n/app_fr.arb (100%) rename {lib => app/lib}/l10n/app_localizations.dart (100%) rename {lib => app/lib}/l10n/app_localizations_en.dart (100%) rename {lib => app/lib}/l10n/app_localizations_fr.dart (100%) rename {lib => app/lib}/main.dart (100%) rename {linux => app/linux}/.gitignore (100%) rename {linux => app/linux}/CMakeLists.txt (100%) rename {linux => app/linux}/flutter/CMakeLists.txt (100%) rename {linux => app/linux}/flutter/generated_plugin_registrant.cc (100%) rename {linux => app/linux}/flutter/generated_plugin_registrant.h (100%) rename {linux => app/linux}/flutter/generated_plugins.cmake (100%) rename {linux => app/linux}/runner/CMakeLists.txt (100%) rename {linux => app/linux}/runner/main.cc (100%) rename {linux => app/linux}/runner/my_application.cc (100%) rename {linux => app/linux}/runner/my_application.h (100%) rename {macos => app/macos}/.gitignore (100%) rename {macos => app/macos}/Flutter/Flutter-Debug.xcconfig (100%) rename {macos => app/macos}/Flutter/Flutter-Release.xcconfig (100%) rename {macos => app/macos}/Flutter/GeneratedPluginRegistrant.swift (100%) rename {macos => app/macos}/Runner.xcodeproj/project.pbxproj (100%) rename {macos => app/macos}/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {macos => app/macos}/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename {macos => app/macos}/Runner.xcworkspace/contents.xcworkspacedata (100%) rename {macos => app/macos}/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {macos => app/macos}/Runner/AppDelegate.swift (100%) rename {macos => app/macos}/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {macos => app/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png (100%) rename {macos => app/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png (100%) rename {macos => app/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png (100%) rename {macos => app/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png (100%) rename {macos => app/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png (100%) rename {macos => app/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png (100%) rename {macos => app/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png (100%) rename {macos => app/macos}/Runner/Base.lproj/MainMenu.xib (100%) rename {macos => app/macos}/Runner/Configs/AppInfo.xcconfig (100%) rename {macos => app/macos}/Runner/Configs/Debug.xcconfig (100%) rename {macos => app/macos}/Runner/Configs/Release.xcconfig (100%) rename {macos => app/macos}/Runner/Configs/Warnings.xcconfig (100%) rename {macos => app/macos}/Runner/DebugProfile.entitlements (100%) rename {macos => app/macos}/Runner/Info.plist (100%) rename {macos => app/macos}/Runner/MainFlutterWindow.swift (100%) rename {macos => app/macos}/Runner/Release.entitlements (100%) rename {macos => app/macos}/RunnerTests/RunnerTests.swift (100%) rename pubspec.yaml => app/pubspec.yaml (100%) rename {test => app/test}/.gitkeep (100%) rename {test => app/test}/features/chat/presentation/viewmodels/chat_viewmodel_test.dart (100%) rename {test => app/test}/features/listings/presentation/screens/seller_profile_screen_test.dart (100%) rename {test => app/test}/features/listings/presentation/viewmodels/seller_profile_viewmodel_test.dart (100%) rename {web => app/web}/favicon.png (100%) rename {web => app/web}/icons/Icon-192.png (100%) rename {web => app/web}/icons/Icon-512.png (100%) rename {web => app/web}/icons/Icon-maskable-192.png (100%) rename {web => app/web}/icons/Icon-maskable-512.png (100%) rename {web => app/web}/index.html (100%) rename {web => app/web}/manifest.json (100%) rename {windows => app/windows}/.gitignore (100%) rename {windows => app/windows}/CMakeLists.txt (100%) rename {windows => app/windows}/flutter/CMakeLists.txt (100%) rename {windows => app/windows}/flutter/generated_plugin_registrant.cc (100%) rename {windows => app/windows}/flutter/generated_plugin_registrant.h (100%) rename {windows => app/windows}/flutter/generated_plugins.cmake (100%) rename {windows => app/windows}/runner/CMakeLists.txt (100%) rename {windows => app/windows}/runner/Runner.rc (100%) rename {windows => app/windows}/runner/flutter_window.cpp (100%) rename {windows => app/windows}/runner/flutter_window.h (100%) rename {windows => app/windows}/runner/main.cpp (100%) rename {windows => app/windows}/runner/resource.h (100%) rename {windows => app/windows}/runner/resources/app_icon.ico (100%) rename {windows => app/windows}/runner/runner.exe.manifest (100%) rename {windows => app/windows}/runner/utils.cpp (100%) rename {windows => app/windows}/runner/utils.h (100%) rename {windows => app/windows}/runner/win32_window.cpp (100%) rename {windows => app/windows}/runner/win32_window.h (100%) create mode 100644 backend/Cargo.toml create mode 100644 backend/src/main.rs delete mode 100644 bookbridge-rust-core/.env.example delete mode 100644 bookbridge-rust-core/Cargo.toml delete mode 100644 bookbridge-rust-core/src/auth.rs delete mode 100644 bookbridge-rust-core/src/config.rs delete mode 100644 bookbridge-rust-core/src/error.rs delete mode 100644 bookbridge-rust-core/src/fapshi.rs delete mode 100644 bookbridge-rust-core/src/lib.rs delete mode 100644 bookbridge-rust-core/src/main.rs delete mode 100644 bookbridge-rust-core/src/routes/escrow.rs delete mode 100644 bookbridge-rust-core/src/routes/health.rs delete mode 100644 bookbridge-rust-core/src/routes/mod.rs delete mode 100644 bookbridge-rust-core/src/routes/webhook.rs delete mode 100644 bookbridge-rust-core/tests/auth_tests.rs delete mode 100644 bookbridge-rust-core/tests/escrow_tests.rs delete mode 100644 bookbridge-rust-core/tests/webhook_tests.rs delete mode 100644 git_final_out.txt delete mode 100644 git_log_final.txt delete mode 100644 git_log_now.txt delete mode 100644 git_merge_push_log.txt delete mode 100644 git_status_debug.txt delete mode 100644 git_status_now.txt delete mode 100644 supabase/favorites_migration.sql delete mode 100644 supabase/feedback_migration.sql delete mode 100644 supabase/functions/fapshi-polling/index.ts delete mode 100644 supabase/functions/process-escrow/index.ts delete mode 100644 supabase/migrations/20260602130000_escrow_payment_flow.sql delete mode 100644 supabase/migrations/20260602224500_update_transactions_status_check.sql delete mode 100644 supabase/migrations/20260611180000_fintech_architecture_fixes.sql delete mode 100644 test.txt rename {landingPage => web}/.gitignore (100%) rename {landingPage => web}/.npmrc (100%) rename {landingPage => web}/check_db.py (100%) rename {landingPage => web}/check_supabase_fast.py (100%) rename {landingPage => web}/check_tx.js (100%) rename {landingPage => web}/jsconfig.json (100%) rename {landingPage => web}/package-lock.json (100%) rename {landingPage => web}/package.json (100%) rename {landingPage => web}/src/app.css (100%) rename {landingPage => web}/src/app.d.ts (100%) rename {landingPage => web}/src/app.html (100%) rename {landingPage => web}/src/lib/assets/Founder.jpg (100%) rename {landingPage => web}/src/lib/assets/favicon.svg (100%) rename {landingPage => web}/src/lib/assets/logo.png (100%) rename {landingPage => web}/src/lib/assets/screenshot.png (100%) rename {landingPage => web}/src/lib/components/AppShowcase.svelte (100%) rename {landingPage => web}/src/lib/components/Features.svelte (100%) rename {landingPage => web}/src/lib/components/Footer.svelte (100%) rename {landingPage => web}/src/lib/components/Founder.svelte (100%) rename {landingPage => web}/src/lib/components/Hero.svelte (100%) rename {landingPage => web}/src/lib/components/HowItWorks.svelte (100%) rename {landingPage => web}/src/lib/components/Navbar.svelte (100%) rename {landingPage => web}/src/lib/components/TrustBar.svelte (100%) rename {landingPage => web}/src/lib/index.js (100%) rename {landingPage => web}/src/lib/links.js (100%) rename {landingPage => web}/src/lib/theme.svelte.js (100%) rename {landingPage => web}/src/routes/+layout.svelte (100%) rename {landingPage => web}/src/routes/+page.svelte (100%) rename {landingPage => web}/src/routes/api/webhooks/campay/+server.js (100%) rename {landingPage => web}/src/routes/api/webhooks/fapshi-payouts/+server.js (100%) rename {landingPage => web}/src/routes/api/webhooks/fapshi/+server.js (100%) rename {landingPage => web}/static/favicon.png (100%) rename {landingPage => web}/static/robots.txt (100%) rename {landingPage => web}/svelte.config.js (100%) rename {landingPage => web}/vite.config.js (100%) diff --git a/.env.example b/.env.example deleted file mode 100644 index 5dac96c..0000000 --- a/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -# Supabase Configuration -# Copy this file to .env and add your actual credentials -SUPABASE_URL=your_supabase_project_url_here -SUPABASE_ANON_KEY=your_supabase_anon_key_here -GOOGLE_CLIENT_ID=your_google_web_client_id_here \ No newline at end of file diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies deleted file mode 100644 index 79315b2..0000000 --- a/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"app_links","path":"/home/dct/.pub-cache/hosted/pub.dev/app_links-6.4.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_core-4.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_messaging-16.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_local_notifications","path":"/home/dct/.pub-cache/hosted/pub.dev/flutter_local_notifications-21.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"geolocator_apple","path":"/home/dct/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.13/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/dct/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_ios","path":"/home/dct/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/package_info_plus-9.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/dct/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/dct/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.6/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/home/dct/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_ios","path":"/home/dct/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.6/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"app_links","path":"/home/dct/.pub-cache/hosted/pub.dev/app_links-6.4.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_core-4.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_messaging-16.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_local_notifications","path":"/home/dct/.pub-cache/hosted/pub.dev/flutter_local_notifications-21.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/dct/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.33/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"geolocator_android","path":"/home/dct/.pub-cache/hosted/pub.dev/geolocator_android-5.0.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/dct/.pub-cache/hosted/pub.dev/google_sign_in_android-6.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_android","path":"/home/dct/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+13/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"package_info_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/package_info_plus-9.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/home/dct/.pub-cache/hosted/pub.dev/path_provider_android-2.2.22/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/dct/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.18/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_android","path":"/home/dct/.pub-cache/hosted/pub.dev/sqflite_android-2.4.2+3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/dct/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.28/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"app_links","path":"/home/dct/.pub-cache/hosted/pub.dev/app_links-6.4.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_selector_macos","path":"/home/dct/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_core-4.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_messaging-16.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_local_notifications","path":"/home/dct/.pub-cache/hosted/pub.dev/flutter_local_notifications-21.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"geolocator_apple","path":"/home/dct/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.13/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/dct/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_macos","path":"/home/dct/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/","native_build":false,"dependencies":["file_selector_macos"],"dev_dependency":false},{"name":"package_info_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/package_info_plus-9.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/dct/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/dct/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.6/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/home/dct/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"/home/dct/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.5/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"app_links_linux","path":"/home/dct/.pub-cache/hosted/pub.dev/app_links_linux-1.0.3/","native_build":false,"dependencies":["gtk"],"dev_dependency":false},{"name":"file_selector_linux","path":"/home/dct/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_local_notifications_linux","path":"/home/dct/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-8.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"geolocator_linux","path":"/home/dct/.pub-cache/hosted/pub.dev/geolocator_linux-0.2.4/","native_build":false,"dependencies":["package_info_plus"],"dev_dependency":false},{"name":"gtk","path":"/home/dct/.pub-cache/hosted/pub.dev/gtk-2.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_linux","path":"/home/dct/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"package_info_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/package_info_plus-9.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/dct/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":false,"dependencies":["url_launcher_linux"],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/dct/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"url_launcher_linux","path":"/home/dct/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"app_links","path":"/home/dct/.pub-cache/hosted/pub.dev/app_links-6.4.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/home/dct/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_core-4.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_local_notifications_windows","path":"/home/dct/.pub-cache/hosted/pub.dev/flutter_local_notifications_windows-3.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"geolocator_windows","path":"/home/dct/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_windows","path":"/home/dct/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"package_info_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/package_info_plus-9.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/dct/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":["url_launcher_windows"],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/dct/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"url_launcher_windows","path":"/home/dct/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"app_links_web","path":"/home/dct/.pub-cache/hosted/pub.dev/app_links_web-1.0.4/","dependencies":[],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_core_web-3.5.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/home/dct/.pub-cache/hosted/pub.dev/firebase_messaging_web-4.1.3/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"geolocator_web","path":"/home/dct/.pub-cache/hosted/pub.dev/geolocator_web-4.1.3/","dependencies":[],"dev_dependency":false},{"name":"google_sign_in_web","path":"/home/dct/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+4/","dependencies":[],"dev_dependency":false},{"name":"image_picker_for_web","path":"/home/dct/.pub-cache/hosted/pub.dev/image_picker_for_web-3.1.1/","dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/package_info_plus-9.0.0/","dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/home/dct/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","dependencies":["url_launcher_web"],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/dct/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/dct/.pub-cache/hosted/pub.dev/url_launcher_web-2.4.2/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"app_links","dependencies":["app_links_linux","app_links_web"]},{"name":"app_links_linux","dependencies":["gtk"]},{"name":"app_links_web","dependencies":[]},{"name":"file_selector_linux","dependencies":[]},{"name":"file_selector_macos","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_local_notifications","dependencies":["flutter_local_notifications_linux","flutter_local_notifications_windows"]},{"name":"flutter_local_notifications_linux","dependencies":[]},{"name":"flutter_local_notifications_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows","geolocator_linux"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_linux","dependencies":["package_info_plus"]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"gtk","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios","image_picker_linux","image_picker_macos","image_picker_windows"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"image_picker_linux","dependencies":["file_selector_linux"]},{"name":"image_picker_macos","dependencies":["file_selector_macos"]},{"name":"image_picker_windows","dependencies":["file_selector_windows"]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["url_launcher_web","url_launcher_windows","url_launcher_linux"]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sqflite","dependencies":["sqflite_android","sqflite_darwin"]},{"name":"sqflite_android","dependencies":[]},{"name":"sqflite_darwin","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2026-05-27 17:25:12.730242","version":"3.38.8","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/ANTIGRAVITY_BOOKBRIDGE_BRIEF_v2.md b/ANTIGRAVITY_BOOKBRIDGE_BRIEF_v2.md deleted file mode 100644 index b43e981..0000000 --- a/ANTIGRAVITY_BOOKBRIDGE_BRIEF_v2.md +++ /dev/null @@ -1,464 +0,0 @@ -# 🤖 Antigravity 2.0 — BookBridge Development Agent Brief (v2) -> Feed this entire document as your starting prompt into Antigravity 2.0. -> NOTE: You have already pulled the latest repo and analyzed its state. -> Issue #14 (APK download link) is confirmed fixed in commit `a0a4b7a`. -> Begin from Issue #15 (screenshot overflow) and Issue #9 (Terms & Conditions), -> then proceed through Priorities 2–7 in order. - ---- - -## 🎯 YOUR MISSION - -You are a senior Flutter/Dart engineer resuming development on **BookBridge** — a peer-to-peer textbook marketplace for Cameroonian students. The lead developer (Mr. DCT) has been away from this repo for ~2 months. Your job is to pick up exactly where he left off and execute the next development sprint based on both the existing roadmap and the strategic recommendations document below. - -**Repository:** https://github.com/DCT-Berinyuy/book-bridge -**Active Branch:** `dev` -**Current Version:** v1.4.0+4 -**Tech Stack:** Flutter 3.10.7+ / Dart, Supabase (PostgreSQL + Auth + Storage + Realtime), Provider, GetIt, go_router, dartz, Fapshi (payments) - ---- - -## 📦 REPO STATE (Already Confirmed) - -- ✅ `dev` and `main` are fully synced, clean, no conflicts -- ✅ Issue #14 (APK link) fixed in commit `a0a4b7a` -- ✅ Fapshi webhook phone formatting fixed (issues #20/#21) -- ✅ Default light theme set -- ✅ 135 commits, 5 releases, 47 Dart files, ~15,000 LOC - -**Read these files before writing any code:** -- `GEMINI.md` — full AI context with architectural decisions -- `lib/injection_container.dart` — all registered dependencies -- `lib/config/router.dart` — all routes -- `lib/features/listings/data/datasources/supabase_listings_datasource.dart` — datasource pattern -- `pubspec.yaml` — current dependencies - ---- - -## 🏗️ ARCHITECTURE OVERVIEW - -### Clean Architecture — 3 Layers -``` -lib/ -├── core/ # Errors, theme, base use cases, shared widgets -├── features/ -│ ├── auth/ # 11 files — Supabase Auth, sign in/up, profile -│ ├── listings/ # 22 files — Browse, sell, search, listing details -│ └── notifications/ # Placeholder only -├── config/ # app_config.dart, router.dart -├── injection_container.dart -└── main.dart -``` - -### Key Patterns -- **State:** `Provider` + `ChangeNotifier` ViewModels -- **DI:** `GetIt` service locator (30+ registered deps) -- **Navigation:** `go_router` with `StatefulShellRoute` -- **Error handling:** `Either` via `dartz` -- **DB:** Supabase PostgreSQL with RLS on all tables - -### Brand Identity: "Knowledge & Trust" -- Scholar Blue: `#1A4D8C` (primary) -- Bridge Orange: `#F2994A` (secondary) -- Growth Green: `#27AE60` (tertiary) -- Font: Montserrat (headings), Inter (body) - ---- - -## ✅ ALREADY BUILT — DO NOT REBUILD - -- User authentication (email/password via Supabase) -- Browse listings (grid, infinite scroll, 50/page) -- Full-text search (PostgreSQL tsvector) -- Sell books (image upload, form validation) -- Profile management -- WhatsApp seller contact -- Category filtering -- Fapshi payments (MTN MoMo + Orange Money) — v1.4.0 -- Multi-language support (EN/FR) -- SvelteKit landing page (book-bridge-three.vercel.app) -- Clean Architecture with 0 flutter analyze issues - ---- - -## 🚧 DEVELOPMENT SPRINT — PRIORITY ORDER - -Work through these in strict order. Complete and commit each before moving to the next. - ---- - -### PRIORITY 1 — Fix Remaining Open Issues - -**Issue #15:** Screenshot overflow on landing page phone widget -- File: `landingPage/` (SvelteKit) -- Find the phone mockup component and fix CSS overflow/clipping on the screenshot images - -**Issue #9:** Missing Terms & Conditions page -- Create `lib/features/auth/presentation/screens/terms_screen.dart` -- Add route `/terms` in `config/router.dart` -- Link from Sign Up screen with checkbox: "I agree to the Terms & Conditions" -- Content to include: - - User responsibilities (accurate listings, honest condition grading) - - Prohibited items (counterfeit, stolen books) - - Payment policy (Fapshi terms, refund conditions) - - Safety guidelines for in-person meetups - - Data privacy statement - - Platform commission disclosure (5–15% success fee) - ---- - -### PRIORITY 2 — Standardized Book Condition Grading System - -**Goal:** Reduce buyer/seller disputes by standardizing how book conditions are described and displayed. Directly addresses the #1 complaint on global platforms like Better World Books. - -**Implementation:** - -1. Update the `condition` field display throughout the app with color-coded badges: - - `new` → Green `#27AE60` - - `like_new` → Teal `#1ABC9C` - - `good` → Scholar Blue `#1A4D8C` - - `fair` → Bridge Orange `#F2994A` - - `poor` → Red `#E74C3C` - -2. Create `lib/core/widgets/condition_badge.dart` — reusable badge widget used on ListingCard and ListingDetailsScreen - -3. Add a **Condition Guide Modal** — tappable info icon on SellScreen and ListingDetailsScreen: - - Create `lib/core/widgets/condition_guide_modal.dart` - - Each condition shows: name, color, description, what to expect - - Content: - ``` - NEW: Unused, unopened, original packaging if applicable - LIKE NEW: Read once, no markings, minimal wear - GOOD: Some highlighting/notes, intact binding, all pages present - FAIR: Heavy use, significant markings, may have creases - POOR: Functional but heavily worn, all content readable - ``` - -4. On SellScreen, replace plain condition dropdown with visual condition selector cards showing color + description - ---- - -### PRIORITY 3 — Offline Cache with sqflite - -**Goal:** Users can browse listings without active internet — critical for Cameroonian low-bandwidth context. - -**Dependencies to add in pubspec.yaml:** -```yaml -sqflite: ^2.3.0 -path: ^1.9.0 -``` - -**Files to create:** -- `lib/core/local_db/local_database.dart` — SQLite setup and schema -- `lib/features/listings/data/datasources/local_listings_datasource.dart` - -**Schema:** -```sql -CREATE TABLE cached_listings ( - id TEXT PRIMARY KEY, - title TEXT, - author TEXT, - price_fcfa INTEGER, - condition TEXT, - image_url TEXT, - description TEXT, - seller_id TEXT, - status TEXT, - category TEXT, - cached_at INTEGER -); -``` - -**Modify `ListingsRepositoryImpl` to:** -- On successful fetch → cache results to SQLite -- On network failure → serve from cache with `OfflineBanner` widget -- Cache TTL: 24 hours (check `cached_at` Unix timestamp) - -**Add `OfflineBanner` widget:** -- Yellow banner at top of HomeScreen: "You're offline — showing saved results" -- Only visible when serving from cache - -**Register `SqfliteCacheService` in `injection_container.dart`** - ---- - -### PRIORITY 4 — Social Impact Tracker (Book-for-Book Model) - -**Goal:** Formalize BookBridge's social mission with measurable impact metrics. Based on Better World Books' model — every transaction generates trackable social good. Critical for investor pitch at PROMOTE 2026. - -**Database — Add to Supabase:** -```sql -CREATE TABLE impact_metrics ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - metric_type TEXT NOT NULL CHECK (metric_type IN ( - 'book_circulated', - 'money_saved', - 'co2_avoided', - 'student_reached' - )), - value FLOAT NOT NULL, - transaction_id UUID, - recorded_at TIMESTAMP DEFAULT NOW() -); - -CREATE TABLE platform_stats ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - total_books_circulated INTEGER DEFAULT 0, - total_students_reached INTEGER DEFAULT 0, - total_money_saved_fcfa BIGINT DEFAULT 0, - total_co2_avoided_kg FLOAT DEFAULT 0, - updated_at TIMESTAMP DEFAULT NOW() -); -``` - -**Calculation logic:** -- `money_saved` = average new book price (15,000 FCFA) − sale price -- `co2_avoided` = 2.7kg CO2 per book reused (industry standard) -- `student_reached` = unique buyers + unique sellers - -**Flutter implementation:** -1. Create `lib/features/impact/` feature -2. `ImpactStatsWidget` — displayed on HomeScreen below the featured carousel: - ``` - 📚 1,247 books circulated - 💰 18.7M FCFA saved by students - 🌱 3.4 tonnes CO2 avoided - ``` -3. Stats fetched from `platform_stats` table (cached locally, updated on each transaction) -4. Animated number counters on first load (use `CountUp` animation) -5. Update `platform_stats` via Supabase trigger after each completed transaction - ---- - -### PRIORITY 5 — Seller Ratings & Trust System - -**Goal:** Verified post-transaction ratings. Only buyers who completed a purchase can rate sellers. Core trust mechanism for investor pitch. - -**Database:** -```sql -CREATE TABLE ratings ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - listing_id UUID REFERENCES listings(id) ON DELETE CASCADE, - buyer_id UUID REFERENCES profiles(id) ON DELETE CASCADE, - seller_id UUID REFERENCES profiles(id) ON DELETE CASCADE, - score INTEGER CHECK (score BETWEEN 1 AND 5), - comment TEXT, - created_at TIMESTAMP DEFAULT NOW(), - UNIQUE(listing_id, buyer_id) -); - -ALTER TABLE profiles ADD COLUMN rating_score FLOAT DEFAULT 0; -ALTER TABLE profiles ADD COLUMN rating_count INTEGER DEFAULT 0; -``` - -**Bayesian Rating Formula:** -``` -adjusted_rating = (v / (v + m)) * R + (m / (v + m)) * C -where: v = rating_count, R = raw average, m = 5, C = global average -``` - -**Flutter:** -1. Create `lib/features/ratings/` feature (domain/data/presentation) -2. `RatingEntity`, `SubmitRatingUseCase`, `GetSellerRatingsUseCase` -3. `RatingViewModel` with Provider -4. `SubmitRatingSheet` — bottom sheet with 5-star selector + optional comment -5. Seller rating badge on `ListingDetailsScreen` and `ProfileScreen` -6. Trigger rating prompt after Fapshi transaction marked complete - ---- - -### PRIORITY 6 — Safety Guidelines & Campus Meetup Zones - -**Goal:** Increase trust and safety for in-person book exchanges. Based on P2P marketplace best practices — explicit safety infrastructure reduces fraud and increases platform confidence. - -**Flutter:** -1. Create `lib/features/safety/presentation/screens/safety_guidelines_screen.dart` -2. Add route `/safety` accessible from ListingDetailsScreen ("Arrange Meetup" section) -3. Content sections: - - **Safe Meetup Locations**: Public campus areas, library entrances, student union buildings - - **What to Check**: Verify book condition before paying, match ISBN if possible - - **Payment Safety**: Always use in-app Fapshi payment, never send money in advance via WhatsApp - - **Report Issues**: Link to report form -4. Add `MeetupTipsCard` widget on `ListingDetailsScreen` below the WhatsApp contact button -5. Create a `campus_zones` table in Supabase for verified safe exchange points: -```sql -CREATE TABLE campus_zones ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - name TEXT NOT NULL, - university TEXT NOT NULL, - city TEXT NOT NULL, - description TEXT, - latitude FLOAT, - longitude FLOAT, - is_verified BOOLEAN DEFAULT FALSE -); -``` -Pre-populate with known ICT University, University of Yaoundé I, University of Buea locations. - ---- - -### PRIORITY 7 — Push Notifications (FCM) - -**Goal:** Notify users about payment confirmations, new listings matching their interests, and listing inquiries. - -**Dependencies:** -```yaml -firebase_messaging: ^14.0.0 -flutter_local_notifications: ^17.0.0 -``` - -**Database:** -```sql -CREATE TABLE notifications ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - user_id UUID REFERENCES profiles(id) ON DELETE CASCADE, - type TEXT NOT NULL, - title TEXT NOT NULL, - body TEXT, - data JSONB, - is_read BOOLEAN DEFAULT FALSE, - created_at TIMESTAMP DEFAULT NOW() -); -``` - -**Notification types:** -- `payment_confirmed` — Fapshi payment success -- `new_inquiry` — Someone contacted about your listing -- `new_listing_match` — New book in a category you've browsed -- `impact_milestone` — "BookBridge just circulated its 500th book! 🎉" - -**Implementation:** -1. Create `lib/core/notifications/notification_service.dart` -2. Update `NotificationsScreen` (currently placeholder) with real notification list -3. Unread badge on bottom nav Notifications icon -4. Impact milestone notifications tie into Priority 4's impact tracker - ---- - -### PRIORITY 8 — Wishlist / Favorites - -**Database:** -```sql -CREATE TABLE wishlists ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - user_id UUID REFERENCES profiles(id) ON DELETE CASCADE, - listing_id UUID REFERENCES listings(id) ON DELETE CASCADE, - created_at TIMESTAMP DEFAULT NOW(), - UNIQUE(user_id, listing_id) -); -``` - -**Flutter:** -1. Create `lib/features/wishlist/` feature -2. Heart icon on `ListingCard` and `ListingDetailsScreen` -3. `WishlistScreen` accessible from Profile tab -4. Optimistic UI updates (toggle immediately, sync to Supabase) -5. `WishlistViewModel` with Provider - ---- - -### PRIORITY 9 — Escrow Payment Flow - -**Goal:** Trust layer on top of existing Fapshi integration. - -**Flow:** -``` -Buyer pays → Funds held in escrow → -Buyer confirms receipt (or 48h auto-release) → -Funds released to seller → Rating prompt shown → Impact metrics updated -``` - -**Database:** -```sql -CREATE TABLE escrow_transactions ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - listing_id UUID REFERENCES listings(id), - buyer_id UUID REFERENCES profiles(id), - seller_id UUID REFERENCES profiles(id), - amount_fcfa INTEGER NOT NULL, - fapshi_transaction_id TEXT, - status TEXT DEFAULT 'held' CHECK ( - status IN ('held', 'released', 'refunded', 'disputed') - ), - held_at TIMESTAMP DEFAULT NOW(), - released_at TIMESTAMP, - release_deadline TIMESTAMP -); -``` - -**Steps:** -1. Modify Fapshi payment flow to route through escrow -2. "Confirm Receipt" button on buyer's transaction history -3. Supabase Edge Function for auto-release after 48h -4. Dispute flow: "There's a problem" → manual review queue -5. On release → trigger rating prompt (Priority 5) + update impact metrics (Priority 4) - ---- - -## 🎨 UI/UX IMPROVEMENTS (Implement Alongside Above) - -- **Shimmer skeleton loaders** on HomeScreen grid — replace `CircularProgressIndicator` -- **Image compression** before upload — max 800px width, 80% quality using `flutter_image_compress` -- **Empty state illustrations** — custom SVG for empty search, empty wishlist, empty profile -- **Book swap badge** on listings — sellers can optionally mark a book as "Swap Available" in addition to sale price -- **Featured listings carousel** refinement — ensure impact stats widget sits cleanly below it - ---- - -## 📋 CODING STANDARDS — NON-NEGOTIABLE - -1. **Zero flutter analyze issues** — run before every commit -2. **Clean Architecture** — every new feature: domain/data/presentation layers -3. **Either pattern** — all repository methods return `Either` -4. **Provider for state** — new ViewModels extend `ChangeNotifier` -5. **Register in GetIt** — all new services/repos/use cases in `injection_container.dart` -6. **Before every commit:** - ```bash - dart fix --apply - flutter analyze - dart format . - ``` -7. **Branch naming:** `feature/condition-grading`, `feature/offline-cache`, `feature/impact-tracker`, etc. -8. **Commit messages:** Conventional commits — `feat:`, `fix:`, `refactor:`, `docs:` - ---- - -## 🏆 CONTEXT: WHY THIS MATTERS - -BookBridge is a candidate for **PROMOTE 2026** — an investor showcase at Palais des Congrès, Yaoundé (June 15–21, 2026). ICT University will present 5 student projects to 200+ investors. **Pre-selection deadline: June 1, 2026.** - -**Features investors will care about most (in order):** -1. **Impact metrics** — books circulated, money saved, CO2 avoided (Priority 4) -2. **Seller ratings** — trust = monetization potential (Priority 5) -3. **Escrow payments** — fraud prevention = scale (Priority 9) -4. **Offline cache** — African market fit = TAM story (Priority 3) -5. **Safety infrastructure** — platform maturity signal (Priority 6) - -The social mission framing (book-for-book model, SDG alignment, B-Corp direction) is what differentiates BookBridge from a generic marketplace. Every feature should reinforce that story. - -Build like investors are watching. 🚀 - ---- - -## 📊 STRATEGIC CONTEXT (From Analysis Document) - -BookBridge should model itself after these global platforms while staying African-first: - -| Platform | Key Lesson for BookBridge | -|---|---| -| Better World Books | Book-for-book donations, impact reporting, B-Corp mission | -| World of Books (Wob) | Author revenue sharing, zero-waste pledge, library sourcing | -| Bookshop.org | 80% margin to local ecosystem partners | -| ThriftBooks | Standardized condition grading, tiered loyalty | -| Kenya's Text Book Centre | Curriculum-aligned inventory, East African market proof | - -**Target metrics to display at PROMOTE 2026:** -- Books circulated: track from day 1 -- Students reached: unique active users -- Money saved: (avg new price − sale price) × transactions -- CO2 avoided: 2.7kg × books reused - ---- - -*Brief v2 prepared by Claude (Anthropic) for Mr. DCT / DevSafe* -*BookBridge v1.4.0 → v2.0.0 sprint | PROMOTE 2026 ready* diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d92b041..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,137 +0,0 @@ -# CHANGELOG - -## 1.3.0 - February 15, 2026 - -### Added - -- **Multi-language Support**: Full support for English and French localization across the app. -- **Fapshi Integration**: Integrated community donation support via a dedicated Fapshi checkout link. -- **SvelteKit Landing Page**: Initial production build of the web front-end. - -### Changed - -- **UI Refinements**: Compacted promotional section for a more native feel (155px height). -- **Design System**: Harmonized UI with "pill" style capsule containers for icons and buttons. -- **Project Structure**: Cleaned up 20+ redundant files and migrated to local `l10n` imports for stability. -- **Git Hygiene**: Comprehensive `.gitignore` updates for a cleaner development environment. - -### Fixed - -- **Layout Overflows**: Resolved persistent "RIGHT OVERFLOWED" and "BOTTOM OVERFLOWED" issues on the home screen. -- **Localization Bug**: Fixed critical "Undefined name 'AppLocalizations'" regression. - ---- - -## 1.2.0 - February 14, 2026 - -### Added - -- **Nearby Books**: Initial implementation of location-based listing discovery. -- **Promo Banners**: Dynamic PageView for promotional messaging. - ---- - -### Added - -- **Custom App Launcher Icon**: Beautiful BookBridge logo with intricate patterns on an open book design -- **App Icon Assets**: Added `assets/app_icon.png` to project resources -- **Adaptive Icons**: Configured adaptive icons for Android with black background - -### Changed - -- Updated `pubspec.yaml` to include app icon configuration -- Integrated `flutter_launcher_icons` package for icon generation - -### Technical - -- Generated launcher icons for both Android and iOS platforms -- Configured adaptive icon foreground and background for Android - ---- - -## 1.0.0 - January 2026 - -### Features Implemented - -#### Authentication - -- Email/password sign-up and sign-in via Supabase Auth -- User profile creation with full name and locality -- Password reset functionality -- Automatic profile creation via database trigger -- Auth state-based navigation - -#### Listings Management - -- Browse available book listings in grid layout -- Infinite scroll pagination (50 items per page) -- Create new listings with image upload -- Image upload to Supabase Storage (`book_images` bucket) -- Delete own listings with confirmation -- View listing details with seller information - -#### Search - -- Full-text search across book titles and authors -- PostgreSQL tsvector-based search with ranking -- Real-time search results - -#### Profile - -- View and edit user profile -- Manage user's own listings -- WhatsApp contact integration -- Sign out functionality - -#### UI/UX - -- Material Design 3 implementation -- "Knowledge & Trust" visual identity - - Scholar Blue (#1A4D8C) primary color - - Bridge Orange (#F2994A) secondary color - - Growth Green (#27AE60) tertiary color -- Google Fonts integration (Montserrat, Inter) -- Bottom navigation bar (Home, Search, Sell, Profile) -- Pull-to-refresh on home screen -- Loading states and error handling -- Empty states with helpful messages - -### Architecture - -- Clean Architecture with Domain/Data/Presentation layers -- Provider state management with ChangeNotifier -- Dependency injection with GetIt -- Navigation with go_router and auth-based redirection -- Error handling with Either pattern (dartz) - -### Database - -- PostgreSQL tables: `profiles`, `listings` -- Row Level Security (RLS) policies -- Full-text search function -- Automatic profile creation trigger -- Indexes for optimized queries - -### Storage - -- Supabase Storage for book images -- Public bucket with RLS policies -- User-specific folder structure - -### Documentation - -- Comprehensive README with architecture overview -- Detailed Supabase setup guide (665 lines) -- Implementation documentation -- Brand identity guide -- Social venture vision document - ---- - -## 0.1.0 - Initial Setup - -- Initial release of BookBridge application -- Flutter project setup with Clean Architecture and MVVM -- Supabase integration planned for Auth, PostgreSQL, and Storage -- Dark theme applied -- Core features (Auth, Home Feed, Search, Sell, Profile, Book Details) outlined diff --git a/GEMINI.md b/GEMINI.md deleted file mode 100644 index a853bb5..0000000 --- a/GEMINI.md +++ /dev/null @@ -1,89 +0,0 @@ -# Gemini CLI Context for BookBridge - -This document provides instructional context for interacting with the BookBridge project. - -## Project Overview - -BookBridge is a mobile application built with **Flutter** that serves as a peer-to-peer marketplace for students in Cameroon to buy and sell used physical books. The backend is powered by **Supabase**, handling user authentication and the database of book listings. - -The project follows a **Clean Architecture** pattern, separating concerns into `Domain`, `Data`, and `Presentation` layers. - -Additionally, there is a `landingPage` directory containing a separate web project built with **SvelteKit** and **Vite**, presumably for marketing or as a web front-end for the service. - -### Key Technologies - -- **Mobile App (Flutter):** - - **State Management:** `provider` with `ChangeNotifier` - - **Navigation:** `go_router` - - **Dependency Injection:** `get_it` - - **Backend Integration:** `supabase_flutter` - - **Error Handling:** `dartz` for functional error handling (`Either`) -- **Landing Page (Web):** - - **Framework:** SvelteKit - - **Build Tool:** Vite -- **Backend:** - - Supabase (Auth, PostgreSQL Database, Storage) - -## Building and Running - -### Flutter Mobile App - -1. **Install Dependencies:** - - ```bash - flutter pub get - ``` - -2. **Configure Environment:** - Create a `.env` file in the project root. You can copy the example: - - ```bash - cp .env.example .env - ``` - - Then, fill in your Supabase project credentials in the `.env` file: - - ``` - SUPABASE_URL=your_supabase_project_url - SUPABASE_ANON_KEY=your_supabase_anon_key - ``` - -3. **Run the App:** - Use the `--dart-define` flags to pass the environment variables from the `.env` file to the Flutter app. - ```bash - flutter run \ - --dart-define="SUPABASE_URL=$(grep SUPABASE_URL .env | cut -d'=' -f2)" \ - --dart-define="SUPABASE_ANON_KEY=$(grep SUPABASE_ANON_KEY .env | cut -d'=' -f2)" \ - --dart-define="GOOGLE_CLIENT_ID=$(grep GOOGLE_CLIENT_ID .env | cut -d'=' -f2)" \ - --dart-define="FAPSHI_API_USER=$(grep FAPSHI_API_USER .env | cut -d'=' -f2)" \ - --dart-define="FAPSHI_API_KEY=$(grep FAPSHI_API_KEY .env | cut -d'=' -f2)" \ - --dart-define="FAPSHI_BASE_URL=$(grep FAPSHI_BASE_URL .env | cut -d'=' -f2)" - ``` - -### SvelteKit Landing Page - -1. **Navigate to Directory:** - - ```bash - cd landingPage - ``` - -2. **Install Dependencies:** - - ```bash - npm install - ``` - -3. **Run the Development Server:** - ```bash - npm run dev - ``` - -## Development Conventions - -- **Architecture:** The codebase is structured using Clean Architecture principles. When adding new features, create or modify files within the `lib/features` directory, respecting the `domain`, `data`, and `presentation` layers. -- **Code Quality:** Maintain high code quality by using the standard Dart/Flutter tools. Before committing, it's good practice to run: - - `flutter analyze` - To check for any static analysis issues. - - `dart format .` - To ensure consistent code formatting. -- **State Management:** App state is managed using the `provider` package. For new UI features requiring state, create a `ChangeNotifier` and provide it to the relevant widget tree. -- **Navigation:** All routing is handled by `go_router`. Add new routes or modify existing ones in `lib/config/router.dart`. diff --git a/README.md b/README.md index 9c0e7b1..e69de29 100644 --- a/README.md +++ b/README.md @@ -1,247 +0,0 @@ -# BookBridge 📚 - -[![Flutter](https://img.shields.io/badge/Flutter-3.10.7+-blue?logo=flutter&style=flat-square)](https://flutter.dev/) -[![Supabase](https://img.shields.io/badge/Supabase-Backend-green?logo=supabase&style=flat-square)](https://supabase.com/) -[![SvelteKit](https://img.shields.io/badge/SvelteKit-Landing%20Page-orange?logo=svelte&style=flat-square)](https://kit.svelte.dev/) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT) -[![Platform](https://img.shields.io/badge/platform-android%20%7C%20ios%20%7C%20web-green?style=flat-square)](https://flutter.dev/) -[![Version](https://img.shields.io/badge/version-1.5.0-brightgreen?style=flat-square)](https://github.com/DCT-Berinyuy/book-bridge) - -> **A Social Venture to End Learning Poverty in Cameroon** - -BookBridge is a peer-to-peer marketplace designed for Cameroonian students to buy and sell used physical books. Powered by Flutter and Supabase, it facilitates affordable access to textbooks and educational resources while enabling students to recycle and monetize their book collections. - -**Our Mission**: To democratize access to education in Cameroon, addressing the crisis where **72% of children** cannot read and understand simple text by age 10. - ---- - -## 📸 Screenshots - -
- Screenshot 1 - Screenshot 2 - Screenshot 3 -
- ---- - -## 🌟 Key Features - -### Core Marketplace -* **User Authentication**: Secure sign-in and profile synchronization via Supabase Auth. -* **Smart Search**: Full-text indexing across book titles and authors using PostgreSQL `tsvector` with relevance ranking. -* **Direct Handover Flow**: Intuitive purchase flow featuring user-to-user coordination. -* **Category Filtering**: Browse books by category (textbooks, novels, references, etc.) with responsive chips. -* **Secure Storage**: Public book cover images hosted securely via bucket policies in Supabase Storage. - -### Automated Escrow System (MoMo Integration) -* **Secure Holds**: Funds are collected via **Fapshi Direct Pay (MoMo/Orange Money)** and held in escrow until the buyer confirms physical handover. -* **5-Day Auto-Release**: Prevents sellers from being ghosted. Escrows are automatically released to the seller after 5 days if no dispute is filed. -* **Status Polling**: A pg_cron background worker Edge Function checks payment status every 5 minutes to automatically resolve transactions stuck in `pending_payment`. -* **Dispute Freeze**: Buyers can report problems to freeze the auto-release timer and trigger admin review. -* **Secure Payouts**: Payout execution is handled entirely server-side (Edge Functions) using database secrets via `app_secrets` (RLS enforced). -* **Audit Logging**: Every API transaction with Fapshi is logged in `fapshi_audit_logs` for transaction history, tracing, and fraud prevention. - ---- - -## 🏗️ Architecture - -BookBridge follows **Clean Architecture** patterns separating business logic, UI, and data layers: - -``` -lib/ -├── core/ # Shared assets, utilities, and components -│ ├── error/ # Functional error handling (Failures, Exceptions) -│ ├── theme/ # Custom Material Design 3 theme -│ └── usecases/ # Base abstract UseCase contracts -├── features/ # Modules encapsulating distinct functionality -│ ├── auth/ # Domain, data, and presentation layers for Auth -│ ├── chat/ # Real-time message exchange -│ ├── favorites/ # Wishlists and saved listings -│ ├── listings/ # Browsing, listing creation, and category search -│ ├── payments/ # Fapshi Direct Pay integration & ViewModels -│ ├── reviews/ # Buyer/Seller trust rating system -│ └── transactions/ # Escrow confirm and dispute handlers -├── config/ # Global configuration -│ ├── app_config.dart # Dart define environment bindings -│ └── router.dart # Route configurations (go_router) -├── injection_container.dart # GetIt dependency injection setup -└── main.dart # Application entry point -``` - -### Escrow Architecture Sequence - -```mermaid -sequenceDiagram - actor Buyer - actor Seller - participant App as Flutter Mobile App - participant Fapshi as Fapshi API - participant Webhook as SvelteKit Webhook - participant DB as Supabase DB - participant Cron as pg_cron / Edge Functions - - Buyer->>App: Clicks "Buy Now" & enters MoMo details - App->>Fapshi: Direct Pay request - Fapshi-->>App: Returns transId (CREATED) - Fapshi->>Webhook: Webhook notification (CREATED/PENDING) - Webhook->>DB: Inserts transaction as 'pending_payment' - Buyer->>Fapshi: Approves USSD Push (MoMo Payment) - Fapshi->>Webhook: Webhook notification (SUCCESSFUL) - Webhook->>DB: Updates transaction status to 'held' & creates escrow - Webhook->>DB: Marks listing as 'sold' - Note over DB: 5-Day Auto-Release timer starts - Seller->>Buyer: Hands over physical book - alt Buyer Confirms Delivery - Buyer->>App: Clicks "Confirm Receipt" - App->>Cron: Calls process-escrow Edge Function (release) - else Cooldown Expired (5 days) - Cron->>DB: Auto-release-expired job triggers - end - Cron->>Fapshi: Payout API request to Seller - Fapshi-->>Cron: Payout SUCCESSFUL - Cron->>DB: Updates status to 'released' and payout successful - DB->>Seller: MoMo Payout Received -``` - ---- - -## 🚀 Getting Started - -### Prerequisites -* Flutter SDK (v3.10.7 or higher) -* Supabase CLI / Account -* Node.js (for SvelteKit Landing Page) - -### Repository Setup -1. Clone the project: - ```bash - git clone https://github.com/DCT-Berinyuy/book-bridge.git - cd book-bridge - ``` -2. Fetch packages: - ```bash - flutter pub get - ``` - -### Configuration -Create a `.env` file in the project root: -```env -SUPABASE_URL=https://your-project.supabase.co -SUPABASE_ANON_KEY=your-anon-key -FAPSHI_API_USER=your-fapshi-user -FAPSHI_API_KEY=your-fapshi-key -FAPSHI_BASE_URL=https://live.fapshi.com -``` - -### Launching the App -Run the application with environments injected using `--dart-define`: -```bash -flutter run \ - --dart-define="SUPABASE_URL=$(grep SUPABASE_URL .env | cut -d'=' -f2)" \ - --dart-define="SUPABASE_ANON_KEY=$(grep SUPABASE_ANON_KEY .env | cut -d'=' -f2)" \ - --dart-define="FAPSHI_API_USER=$(grep FAPSHI_API_USER .env | cut -d'=' -f2)" \ - --dart-define="FAPSHI_API_KEY=$(grep FAPSHI_API_KEY .env | cut -d'=' -f2)" -``` - -### Running Landing Page (SvelteKit) -```bash -cd landingPage -npm install -npm run dev -``` - ---- - -## 📊 Database Schema Highlights - -### `transactions` Table -Stores buyer purchase logs and commissions. -```sql -CREATE TABLE public.transactions ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - listing_id UUID NOT NULL REFERENCES public.listings(id) ON DELETE CASCADE, - buyer_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, - seller_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, - amount INTEGER NOT NULL CHECK (amount > 0), - payment_reference TEXT UNIQUE NOT NULL, - status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'pending_payment', 'successful', 'failed', 'held', 'disputed')), - payout_status TEXT DEFAULT 'pending', - payout_reference TEXT, - commission_amount INTEGER, - created_at TIMESTAMPTZ DEFAULT NOW() -); -``` - -### `escrow_transactions` Table -Manages the auto-release deadline timer. -```sql -CREATE TABLE public.escrow_transactions ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - transaction_id UUID NOT NULL REFERENCES public.transactions(id) ON DELETE CASCADE, - status TEXT NOT NULL DEFAULT 'held' CHECK (status IN ('held', 'released', 'refunded', 'disputed')), - dispute_reason TEXT, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - release_deadline TIMESTAMP WITH TIME ZONE GENERATED ALWAYS AS (public.add_5_days(created_at)) STORED -); -``` - -### `fapshi_audit_logs` Table -Maintains payout auditing logs for administrative review. -```sql -CREATE TABLE public.fapshi_audit_logs ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - transaction_id UUID REFERENCES public.transactions(id) ON DELETE SET NULL, - endpoint TEXT NOT NULL, - request_payload JSONB, - response_payload JSONB, - status_code INTEGER, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - ---- - -## 🧭 Navigation & Routes - -The application leverages `go_router` supporting authentication redirects and shell layouts: - -| Route | Screen | Auth? | Description | -| :--- | :--- | :--- | :--- | -| `/` | SplashScreen | No | Sessions startup and auth routing | -| `/sign-in` | SignInScreen | No | User login portal | -| `/home` | HomeScreen | Yes | Browse books listings feed | -| `/search` | SearchScreen | Yes | Run FTS indexing search queries | -| `/sell` | SellScreen | Yes | Book details registration and storage uploads | -| `/profile` | ProfileScreen | Yes | User details, feedback, and active listings | -| `/listing/:id`| ListingDetailsScreen | Yes | Specific book details & checkout portal | - ---- - -## 🤝 Contributing Guidelines - -1. Fork the Repository. -2. Create a Feature Branch (`git checkout -b feature/AmazingFeature`). -3. Follow the Clean Architecture design rules. -4. Ensure files are properly formatted: - ```bash - dart format . - flutter analyze - ``` -5. Commit your Changes (`git commit -m 'feat: Add AmazingFeature'`). -6. Push to Branch (`git push origin feature/AmazingFeature`). -7. Open a Pull Request. - ---- - -## 📄 License - -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. - ---- - -
- Made with ❤️ for Cameroonian students
- Democratizing access to knowledge, one book at a time. -
diff --git a/.gitignore b/app/.gitignore similarity index 100% rename from .gitignore rename to app/.gitignore diff --git a/.metadata b/app/.metadata similarity index 100% rename from .metadata rename to app/.metadata diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..9c0e7b1 --- /dev/null +++ b/app/README.md @@ -0,0 +1,247 @@ +# BookBridge 📚 + +[![Flutter](https://img.shields.io/badge/Flutter-3.10.7+-blue?logo=flutter&style=flat-square)](https://flutter.dev/) +[![Supabase](https://img.shields.io/badge/Supabase-Backend-green?logo=supabase&style=flat-square)](https://supabase.com/) +[![SvelteKit](https://img.shields.io/badge/SvelteKit-Landing%20Page-orange?logo=svelte&style=flat-square)](https://kit.svelte.dev/) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT) +[![Platform](https://img.shields.io/badge/platform-android%20%7C%20ios%20%7C%20web-green?style=flat-square)](https://flutter.dev/) +[![Version](https://img.shields.io/badge/version-1.5.0-brightgreen?style=flat-square)](https://github.com/DCT-Berinyuy/book-bridge) + +> **A Social Venture to End Learning Poverty in Cameroon** + +BookBridge is a peer-to-peer marketplace designed for Cameroonian students to buy and sell used physical books. Powered by Flutter and Supabase, it facilitates affordable access to textbooks and educational resources while enabling students to recycle and monetize their book collections. + +**Our Mission**: To democratize access to education in Cameroon, addressing the crisis where **72% of children** cannot read and understand simple text by age 10. + +--- + +## 📸 Screenshots + +
+ Screenshot 1 + Screenshot 2 + Screenshot 3 +
+ +--- + +## 🌟 Key Features + +### Core Marketplace +* **User Authentication**: Secure sign-in and profile synchronization via Supabase Auth. +* **Smart Search**: Full-text indexing across book titles and authors using PostgreSQL `tsvector` with relevance ranking. +* **Direct Handover Flow**: Intuitive purchase flow featuring user-to-user coordination. +* **Category Filtering**: Browse books by category (textbooks, novels, references, etc.) with responsive chips. +* **Secure Storage**: Public book cover images hosted securely via bucket policies in Supabase Storage. + +### Automated Escrow System (MoMo Integration) +* **Secure Holds**: Funds are collected via **Fapshi Direct Pay (MoMo/Orange Money)** and held in escrow until the buyer confirms physical handover. +* **5-Day Auto-Release**: Prevents sellers from being ghosted. Escrows are automatically released to the seller after 5 days if no dispute is filed. +* **Status Polling**: A pg_cron background worker Edge Function checks payment status every 5 minutes to automatically resolve transactions stuck in `pending_payment`. +* **Dispute Freeze**: Buyers can report problems to freeze the auto-release timer and trigger admin review. +* **Secure Payouts**: Payout execution is handled entirely server-side (Edge Functions) using database secrets via `app_secrets` (RLS enforced). +* **Audit Logging**: Every API transaction with Fapshi is logged in `fapshi_audit_logs` for transaction history, tracing, and fraud prevention. + +--- + +## 🏗️ Architecture + +BookBridge follows **Clean Architecture** patterns separating business logic, UI, and data layers: + +``` +lib/ +├── core/ # Shared assets, utilities, and components +│ ├── error/ # Functional error handling (Failures, Exceptions) +│ ├── theme/ # Custom Material Design 3 theme +│ └── usecases/ # Base abstract UseCase contracts +├── features/ # Modules encapsulating distinct functionality +│ ├── auth/ # Domain, data, and presentation layers for Auth +│ ├── chat/ # Real-time message exchange +│ ├── favorites/ # Wishlists and saved listings +│ ├── listings/ # Browsing, listing creation, and category search +│ ├── payments/ # Fapshi Direct Pay integration & ViewModels +│ ├── reviews/ # Buyer/Seller trust rating system +│ └── transactions/ # Escrow confirm and dispute handlers +├── config/ # Global configuration +│ ├── app_config.dart # Dart define environment bindings +│ └── router.dart # Route configurations (go_router) +├── injection_container.dart # GetIt dependency injection setup +└── main.dart # Application entry point +``` + +### Escrow Architecture Sequence + +```mermaid +sequenceDiagram + actor Buyer + actor Seller + participant App as Flutter Mobile App + participant Fapshi as Fapshi API + participant Webhook as SvelteKit Webhook + participant DB as Supabase DB + participant Cron as pg_cron / Edge Functions + + Buyer->>App: Clicks "Buy Now" & enters MoMo details + App->>Fapshi: Direct Pay request + Fapshi-->>App: Returns transId (CREATED) + Fapshi->>Webhook: Webhook notification (CREATED/PENDING) + Webhook->>DB: Inserts transaction as 'pending_payment' + Buyer->>Fapshi: Approves USSD Push (MoMo Payment) + Fapshi->>Webhook: Webhook notification (SUCCESSFUL) + Webhook->>DB: Updates transaction status to 'held' & creates escrow + Webhook->>DB: Marks listing as 'sold' + Note over DB: 5-Day Auto-Release timer starts + Seller->>Buyer: Hands over physical book + alt Buyer Confirms Delivery + Buyer->>App: Clicks "Confirm Receipt" + App->>Cron: Calls process-escrow Edge Function (release) + else Cooldown Expired (5 days) + Cron->>DB: Auto-release-expired job triggers + end + Cron->>Fapshi: Payout API request to Seller + Fapshi-->>Cron: Payout SUCCESSFUL + Cron->>DB: Updates status to 'released' and payout successful + DB->>Seller: MoMo Payout Received +``` + +--- + +## 🚀 Getting Started + +### Prerequisites +* Flutter SDK (v3.10.7 or higher) +* Supabase CLI / Account +* Node.js (for SvelteKit Landing Page) + +### Repository Setup +1. Clone the project: + ```bash + git clone https://github.com/DCT-Berinyuy/book-bridge.git + cd book-bridge + ``` +2. Fetch packages: + ```bash + flutter pub get + ``` + +### Configuration +Create a `.env` file in the project root: +```env +SUPABASE_URL=https://your-project.supabase.co +SUPABASE_ANON_KEY=your-anon-key +FAPSHI_API_USER=your-fapshi-user +FAPSHI_API_KEY=your-fapshi-key +FAPSHI_BASE_URL=https://live.fapshi.com +``` + +### Launching the App +Run the application with environments injected using `--dart-define`: +```bash +flutter run \ + --dart-define="SUPABASE_URL=$(grep SUPABASE_URL .env | cut -d'=' -f2)" \ + --dart-define="SUPABASE_ANON_KEY=$(grep SUPABASE_ANON_KEY .env | cut -d'=' -f2)" \ + --dart-define="FAPSHI_API_USER=$(grep FAPSHI_API_USER .env | cut -d'=' -f2)" \ + --dart-define="FAPSHI_API_KEY=$(grep FAPSHI_API_KEY .env | cut -d'=' -f2)" +``` + +### Running Landing Page (SvelteKit) +```bash +cd landingPage +npm install +npm run dev +``` + +--- + +## 📊 Database Schema Highlights + +### `transactions` Table +Stores buyer purchase logs and commissions. +```sql +CREATE TABLE public.transactions ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + listing_id UUID NOT NULL REFERENCES public.listings(id) ON DELETE CASCADE, + buyer_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, + seller_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, + amount INTEGER NOT NULL CHECK (amount > 0), + payment_reference TEXT UNIQUE NOT NULL, + status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'pending_payment', 'successful', 'failed', 'held', 'disputed')), + payout_status TEXT DEFAULT 'pending', + payout_reference TEXT, + commission_amount INTEGER, + created_at TIMESTAMPTZ DEFAULT NOW() +); +``` + +### `escrow_transactions` Table +Manages the auto-release deadline timer. +```sql +CREATE TABLE public.escrow_transactions ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + transaction_id UUID NOT NULL REFERENCES public.transactions(id) ON DELETE CASCADE, + status TEXT NOT NULL DEFAULT 'held' CHECK (status IN ('held', 'released', 'refunded', 'disputed')), + dispute_reason TEXT, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + release_deadline TIMESTAMP WITH TIME ZONE GENERATED ALWAYS AS (public.add_5_days(created_at)) STORED +); +``` + +### `fapshi_audit_logs` Table +Maintains payout auditing logs for administrative review. +```sql +CREATE TABLE public.fapshi_audit_logs ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + transaction_id UUID REFERENCES public.transactions(id) ON DELETE SET NULL, + endpoint TEXT NOT NULL, + request_payload JSONB, + response_payload JSONB, + status_code INTEGER, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); +``` + +--- + +## 🧭 Navigation & Routes + +The application leverages `go_router` supporting authentication redirects and shell layouts: + +| Route | Screen | Auth? | Description | +| :--- | :--- | :--- | :--- | +| `/` | SplashScreen | No | Sessions startup and auth routing | +| `/sign-in` | SignInScreen | No | User login portal | +| `/home` | HomeScreen | Yes | Browse books listings feed | +| `/search` | SearchScreen | Yes | Run FTS indexing search queries | +| `/sell` | SellScreen | Yes | Book details registration and storage uploads | +| `/profile` | ProfileScreen | Yes | User details, feedback, and active listings | +| `/listing/:id`| ListingDetailsScreen | Yes | Specific book details & checkout portal | + +--- + +## 🤝 Contributing Guidelines + +1. Fork the Repository. +2. Create a Feature Branch (`git checkout -b feature/AmazingFeature`). +3. Follow the Clean Architecture design rules. +4. Ensure files are properly formatted: + ```bash + dart format . + flutter analyze + ``` +5. Commit your Changes (`git commit -m 'feat: Add AmazingFeature'`). +6. Push to Branch (`git push origin feature/AmazingFeature`). +7. Open a Pull Request. + +--- + +## 📄 License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +--- + +
+ Made with ❤️ for Cameroonian students
+ Democratizing access to knowledge, one book at a time. +
diff --git a/analysis_options.yaml b/app/analysis_options.yaml similarity index 100% rename from analysis_options.yaml rename to app/analysis_options.yaml diff --git a/android/.gitignore b/app/android/.gitignore similarity index 100% rename from android/.gitignore rename to app/android/.gitignore diff --git a/android/app/build.gradle.kts b/app/android/app/build.gradle.kts similarity index 100% rename from android/app/build.gradle.kts rename to app/android/app/build.gradle.kts diff --git a/android/app/google-services.json b/app/android/app/google-services.json similarity index 100% rename from android/app/google-services.json rename to app/android/app/google-services.json diff --git a/android/app/src/debug/AndroidManifest.xml b/app/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from android/app/src/debug/AndroidManifest.xml rename to app/android/app/src/debug/AndroidManifest.xml diff --git a/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml similarity index 100% rename from android/app/src/main/AndroidManifest.xml rename to app/android/app/src/main/AndroidManifest.xml diff --git a/android/app/src/main/kotlin/com/example/book_bridge/MainActivity.kt b/app/android/app/src/main/kotlin/com/example/book_bridge/MainActivity.kt similarity index 100% rename from android/app/src/main/kotlin/com/example/book_bridge/MainActivity.kt rename to app/android/app/src/main/kotlin/com/example/book_bridge/MainActivity.kt diff --git a/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/app/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png similarity index 100% rename from android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png rename to app/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png diff --git a/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/app/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png similarity index 100% rename from android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png rename to app/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/app/android/app/src/main/res/drawable-v21/launch_background.xml similarity index 100% rename from android/app/src/main/res/drawable-v21/launch_background.xml rename to app/android/app/src/main/res/drawable-v21/launch_background.xml diff --git a/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/app/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png similarity index 100% rename from android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png rename to app/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/app/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png similarity index 100% rename from android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png rename to app/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/app/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png similarity index 100% rename from android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png rename to app/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png diff --git a/android/app/src/main/res/drawable/launch_background.xml b/app/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from android/app/src/main/res/drawable/launch_background.xml rename to app/android/app/src/main/res/drawable/launch_background.xml diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/android/app/src/main/res/values-night/styles.xml b/app/android/app/src/main/res/values-night/styles.xml similarity index 100% rename from android/app/src/main/res/values-night/styles.xml rename to app/android/app/src/main/res/values-night/styles.xml diff --git a/android/app/src/main/res/values/colors.xml b/app/android/app/src/main/res/values/colors.xml similarity index 100% rename from android/app/src/main/res/values/colors.xml rename to app/android/app/src/main/res/values/colors.xml diff --git a/android/app/src/main/res/values/styles.xml b/app/android/app/src/main/res/values/styles.xml similarity index 100% rename from android/app/src/main/res/values/styles.xml rename to app/android/app/src/main/res/values/styles.xml diff --git a/android/app/src/profile/AndroidManifest.xml b/app/android/app/src/profile/AndroidManifest.xml similarity index 100% rename from android/app/src/profile/AndroidManifest.xml rename to app/android/app/src/profile/AndroidManifest.xml diff --git a/android/build.gradle.kts b/app/android/build.gradle.kts similarity index 100% rename from android/build.gradle.kts rename to app/android/build.gradle.kts diff --git a/android/gradle.properties b/app/android/gradle.properties similarity index 100% rename from android/gradle.properties rename to app/android/gradle.properties diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/app/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from android/gradle/wrapper/gradle-wrapper.properties rename to app/android/gradle/wrapper/gradle-wrapper.properties diff --git a/android/settings.gradle.kts b/app/android/settings.gradle.kts similarity index 100% rename from android/settings.gradle.kts rename to app/android/settings.gradle.kts diff --git a/assets/Antigravity_Prompt_BookBridge_Rust_Phase1.md b/app/assets/Antigravity_Prompt_BookBridge_Rust_Phase1.md similarity index 100% rename from assets/Antigravity_Prompt_BookBridge_Rust_Phase1.md rename to app/assets/Antigravity_Prompt_BookBridge_Rust_Phase1.md diff --git a/assets/Antigravity_Prompt_BookBridge_Rust_Phase2.md b/app/assets/Antigravity_Prompt_BookBridge_Rust_Phase2.md similarity index 100% rename from assets/Antigravity_Prompt_BookBridge_Rust_Phase2.md rename to app/assets/Antigravity_Prompt_BookBridge_Rust_Phase2.md diff --git a/assets/BookBridge_v2_Implementation_Plan.md b/app/assets/BookBridge_v2_Implementation_Plan.md similarity index 100% rename from assets/BookBridge_v2_Implementation_Plan.md rename to app/assets/BookBridge_v2_Implementation_Plan.md diff --git a/assets/Founder.jpg b/app/assets/Founder.jpg similarity index 100% rename from assets/Founder.jpg rename to app/assets/Founder.jpg diff --git a/assets/app_icon.png b/app/assets/app_icon.png similarity index 100% rename from assets/app_icon.png rename to app/assets/app_icon.png diff --git a/assets/flow_diagram.png b/app/assets/flow_diagram.png similarity index 100% rename from assets/flow_diagram.png rename to app/assets/flow_diagram.png diff --git a/assets/logo.png b/app/assets/logo.png similarity index 100% rename from assets/logo.png rename to app/assets/logo.png diff --git a/assets/sreenshots/screenshot1.png b/app/assets/sreenshots/screenshot1.png similarity index 100% rename from assets/sreenshots/screenshot1.png rename to app/assets/sreenshots/screenshot1.png diff --git a/assets/sreenshots/screenshot2.png b/app/assets/sreenshots/screenshot2.png similarity index 100% rename from assets/sreenshots/screenshot2.png rename to app/assets/sreenshots/screenshot2.png diff --git a/assets/sreenshots/screenshot3.png b/app/assets/sreenshots/screenshot3.png similarity index 100% rename from assets/sreenshots/screenshot3.png rename to app/assets/sreenshots/screenshot3.png diff --git a/firebase.json b/app/firebase.json similarity index 100% rename from firebase.json rename to app/firebase.json diff --git a/ios/.gitignore b/app/ios/.gitignore similarity index 100% rename from ios/.gitignore rename to app/ios/.gitignore diff --git a/ios/Flutter/AppFrameworkInfo.plist b/app/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from ios/Flutter/AppFrameworkInfo.plist rename to app/ios/Flutter/AppFrameworkInfo.plist diff --git a/ios/Flutter/Debug.xcconfig b/app/ios/Flutter/Debug.xcconfig similarity index 100% rename from ios/Flutter/Debug.xcconfig rename to app/ios/Flutter/Debug.xcconfig diff --git a/ios/Flutter/Release.xcconfig b/app/ios/Flutter/Release.xcconfig similarity index 100% rename from ios/Flutter/Release.xcconfig rename to app/ios/Flutter/Release.xcconfig diff --git a/ios/Runner.xcodeproj/project.pbxproj b/app/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from ios/Runner.xcodeproj/project.pbxproj rename to app/ios/Runner.xcodeproj/project.pbxproj diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/app/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from ios/Runner.xcworkspace/contents.xcworkspacedata rename to app/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/ios/Runner/AppDelegate.swift b/app/ios/Runner/AppDelegate.swift similarity index 100% rename from ios/Runner/AppDelegate.swift rename to app/ios/Runner/AppDelegate.swift diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/app/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from ios/Runner/Base.lproj/LaunchScreen.storyboard rename to app/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/ios/Runner/Base.lproj/Main.storyboard b/app/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from ios/Runner/Base.lproj/Main.storyboard rename to app/ios/Runner/Base.lproj/Main.storyboard diff --git a/ios/Runner/Info.plist b/app/ios/Runner/Info.plist similarity index 100% rename from ios/Runner/Info.plist rename to app/ios/Runner/Info.plist diff --git a/ios/Runner/Runner-Bridging-Header.h b/app/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from ios/Runner/Runner-Bridging-Header.h rename to app/ios/Runner/Runner-Bridging-Header.h diff --git a/ios/RunnerTests/RunnerTests.swift b/app/ios/RunnerTests/RunnerTests.swift similarity index 100% rename from ios/RunnerTests/RunnerTests.swift rename to app/ios/RunnerTests/RunnerTests.swift diff --git a/lib/config/app_config.dart b/app/lib/config/app_config.dart similarity index 100% rename from lib/config/app_config.dart rename to app/lib/config/app_config.dart diff --git a/lib/config/router.dart b/app/lib/config/router.dart similarity index 100% rename from lib/config/router.dart rename to app/lib/config/router.dart diff --git a/lib/core/constants/categories.dart b/app/lib/core/constants/categories.dart similarity index 100% rename from lib/core/constants/categories.dart rename to app/lib/core/constants/categories.dart diff --git a/lib/core/error/exceptions.dart b/app/lib/core/error/exceptions.dart similarity index 100% rename from lib/core/error/exceptions.dart rename to app/lib/core/error/exceptions.dart diff --git a/lib/core/error/failures.dart b/app/lib/core/error/failures.dart similarity index 100% rename from lib/core/error/failures.dart rename to app/lib/core/error/failures.dart diff --git a/lib/core/local_db/local_database.dart b/app/lib/core/local_db/local_database.dart similarity index 100% rename from lib/core/local_db/local_database.dart rename to app/lib/core/local_db/local_database.dart diff --git a/lib/core/presentation/viewmodels/theme_viewmodel.dart b/app/lib/core/presentation/viewmodels/theme_viewmodel.dart similarity index 100% rename from lib/core/presentation/viewmodels/theme_viewmodel.dart rename to app/lib/core/presentation/viewmodels/theme_viewmodel.dart diff --git a/lib/core/presentation/widgets/notification_icon.dart b/app/lib/core/presentation/widgets/notification_icon.dart similarity index 100% rename from lib/core/presentation/widgets/notification_icon.dart rename to app/lib/core/presentation/widgets/notification_icon.dart diff --git a/lib/core/presentation/widgets/offline_banner.dart b/app/lib/core/presentation/widgets/offline_banner.dart similarity index 100% rename from lib/core/presentation/widgets/offline_banner.dart rename to app/lib/core/presentation/widgets/offline_banner.dart diff --git a/lib/core/presentation/widgets/scaffold_with_navbar.dart b/app/lib/core/presentation/widgets/scaffold_with_navbar.dart similarity index 100% rename from lib/core/presentation/widgets/scaffold_with_navbar.dart rename to app/lib/core/presentation/widgets/scaffold_with_navbar.dart diff --git a/lib/core/theme/app_theme.dart b/app/lib/core/theme/app_theme.dart similarity index 100% rename from lib/core/theme/app_theme.dart rename to app/lib/core/theme/app_theme.dart diff --git a/lib/core/usecases/usecase.dart b/app/lib/core/usecases/usecase.dart similarity index 100% rename from lib/core/usecases/usecase.dart rename to app/lib/core/usecases/usecase.dart diff --git a/lib/features/auth/data/datasources/supabase_auth_data_source.dart b/app/lib/features/auth/data/datasources/supabase_auth_data_source.dart similarity index 100% rename from lib/features/auth/data/datasources/supabase_auth_data_source.dart rename to app/lib/features/auth/data/datasources/supabase_auth_data_source.dart diff --git a/lib/features/auth/data/models/user_model.dart b/app/lib/features/auth/data/models/user_model.dart similarity index 100% rename from lib/features/auth/data/models/user_model.dart rename to app/lib/features/auth/data/models/user_model.dart diff --git a/lib/features/auth/data/repositories/auth_repository_impl.dart b/app/lib/features/auth/data/repositories/auth_repository_impl.dart similarity index 100% rename from lib/features/auth/data/repositories/auth_repository_impl.dart rename to app/lib/features/auth/data/repositories/auth_repository_impl.dart diff --git a/lib/features/auth/domain/entities/user.dart b/app/lib/features/auth/domain/entities/user.dart similarity index 100% rename from lib/features/auth/domain/entities/user.dart rename to app/lib/features/auth/domain/entities/user.dart diff --git a/lib/features/auth/domain/repositories/auth_repository.dart b/app/lib/features/auth/domain/repositories/auth_repository.dart similarity index 100% rename from lib/features/auth/domain/repositories/auth_repository.dart rename to app/lib/features/auth/domain/repositories/auth_repository.dart diff --git a/lib/features/auth/domain/usecases/get_current_user_usecase.dart b/app/lib/features/auth/domain/usecases/get_current_user_usecase.dart similarity index 100% rename from lib/features/auth/domain/usecases/get_current_user_usecase.dart rename to app/lib/features/auth/domain/usecases/get_current_user_usecase.dart diff --git a/lib/features/auth/domain/usecases/send_password_reset_email_usecase.dart b/app/lib/features/auth/domain/usecases/send_password_reset_email_usecase.dart similarity index 100% rename from lib/features/auth/domain/usecases/send_password_reset_email_usecase.dart rename to app/lib/features/auth/domain/usecases/send_password_reset_email_usecase.dart diff --git a/lib/features/auth/domain/usecases/sign_in_usecase.dart b/app/lib/features/auth/domain/usecases/sign_in_usecase.dart similarity index 100% rename from lib/features/auth/domain/usecases/sign_in_usecase.dart rename to app/lib/features/auth/domain/usecases/sign_in_usecase.dart diff --git a/lib/features/auth/domain/usecases/sign_in_with_google_usecase.dart b/app/lib/features/auth/domain/usecases/sign_in_with_google_usecase.dart similarity index 100% rename from lib/features/auth/domain/usecases/sign_in_with_google_usecase.dart rename to app/lib/features/auth/domain/usecases/sign_in_with_google_usecase.dart diff --git a/lib/features/auth/domain/usecases/sign_out_usecase.dart b/app/lib/features/auth/domain/usecases/sign_out_usecase.dart similarity index 100% rename from lib/features/auth/domain/usecases/sign_out_usecase.dart rename to app/lib/features/auth/domain/usecases/sign_out_usecase.dart diff --git a/lib/features/auth/domain/usecases/sign_up_usecase.dart b/app/lib/features/auth/domain/usecases/sign_up_usecase.dart similarity index 100% rename from lib/features/auth/domain/usecases/sign_up_usecase.dart rename to app/lib/features/auth/domain/usecases/sign_up_usecase.dart diff --git a/lib/features/auth/domain/usecases/update_user_usecase.dart b/app/lib/features/auth/domain/usecases/update_user_usecase.dart similarity index 100% rename from lib/features/auth/domain/usecases/update_user_usecase.dart rename to app/lib/features/auth/domain/usecases/update_user_usecase.dart diff --git a/lib/features/auth/presentation/screens/complete_profile_screen.dart b/app/lib/features/auth/presentation/screens/complete_profile_screen.dart similarity index 100% rename from lib/features/auth/presentation/screens/complete_profile_screen.dart rename to app/lib/features/auth/presentation/screens/complete_profile_screen.dart diff --git a/lib/features/auth/presentation/screens/edit_profile_screen.dart b/app/lib/features/auth/presentation/screens/edit_profile_screen.dart similarity index 100% rename from lib/features/auth/presentation/screens/edit_profile_screen.dart rename to app/lib/features/auth/presentation/screens/edit_profile_screen.dart diff --git a/lib/features/auth/presentation/screens/sign_in_screen.dart b/app/lib/features/auth/presentation/screens/sign_in_screen.dart similarity index 100% rename from lib/features/auth/presentation/screens/sign_in_screen.dart rename to app/lib/features/auth/presentation/screens/sign_in_screen.dart diff --git a/lib/features/auth/presentation/screens/sign_up_screen.dart b/app/lib/features/auth/presentation/screens/sign_up_screen.dart similarity index 100% rename from lib/features/auth/presentation/screens/sign_up_screen.dart rename to app/lib/features/auth/presentation/screens/sign_up_screen.dart diff --git a/lib/features/auth/presentation/screens/terms_screen.dart b/app/lib/features/auth/presentation/screens/terms_screen.dart similarity index 100% rename from lib/features/auth/presentation/screens/terms_screen.dart rename to app/lib/features/auth/presentation/screens/terms_screen.dart diff --git a/lib/features/auth/presentation/viewmodels/auth_viewmodel.dart b/app/lib/features/auth/presentation/viewmodels/auth_viewmodel.dart similarity index 100% rename from lib/features/auth/presentation/viewmodels/auth_viewmodel.dart rename to app/lib/features/auth/presentation/viewmodels/auth_viewmodel.dart diff --git a/lib/features/auth/presentation/widgets/marketplace_agreement_sheet.dart b/app/lib/features/auth/presentation/widgets/marketplace_agreement_sheet.dart similarity index 100% rename from lib/features/auth/presentation/widgets/marketplace_agreement_sheet.dart rename to app/lib/features/auth/presentation/widgets/marketplace_agreement_sheet.dart diff --git a/lib/features/chat/data/datasources/supabase_chat_data_source.dart b/app/lib/features/chat/data/datasources/supabase_chat_data_source.dart similarity index 100% rename from lib/features/chat/data/datasources/supabase_chat_data_source.dart rename to app/lib/features/chat/data/datasources/supabase_chat_data_source.dart diff --git a/lib/features/chat/data/models/message_model.dart b/app/lib/features/chat/data/models/message_model.dart similarity index 100% rename from lib/features/chat/data/models/message_model.dart rename to app/lib/features/chat/data/models/message_model.dart diff --git a/lib/features/chat/data/repositories/chat_repository_impl.dart b/app/lib/features/chat/data/repositories/chat_repository_impl.dart similarity index 100% rename from lib/features/chat/data/repositories/chat_repository_impl.dart rename to app/lib/features/chat/data/repositories/chat_repository_impl.dart diff --git a/lib/features/chat/domain/entities/conversation.dart b/app/lib/features/chat/domain/entities/conversation.dart similarity index 100% rename from lib/features/chat/domain/entities/conversation.dart rename to app/lib/features/chat/domain/entities/conversation.dart diff --git a/lib/features/chat/domain/entities/message.dart b/app/lib/features/chat/domain/entities/message.dart similarity index 100% rename from lib/features/chat/domain/entities/message.dart rename to app/lib/features/chat/domain/entities/message.dart diff --git a/lib/features/chat/domain/repositories/chat_repository.dart b/app/lib/features/chat/domain/repositories/chat_repository.dart similarity index 100% rename from lib/features/chat/domain/repositories/chat_repository.dart rename to app/lib/features/chat/domain/repositories/chat_repository.dart diff --git a/lib/features/chat/presentation/screens/chat_list_screen.dart b/app/lib/features/chat/presentation/screens/chat_list_screen.dart similarity index 100% rename from lib/features/chat/presentation/screens/chat_list_screen.dart rename to app/lib/features/chat/presentation/screens/chat_list_screen.dart diff --git a/lib/features/chat/presentation/screens/chat_screen.dart b/app/lib/features/chat/presentation/screens/chat_screen.dart similarity index 100% rename from lib/features/chat/presentation/screens/chat_screen.dart rename to app/lib/features/chat/presentation/screens/chat_screen.dart diff --git a/lib/features/chat/presentation/viewmodels/chat_viewmodel.dart b/app/lib/features/chat/presentation/viewmodels/chat_viewmodel.dart similarity index 100% rename from lib/features/chat/presentation/viewmodels/chat_viewmodel.dart rename to app/lib/features/chat/presentation/viewmodels/chat_viewmodel.dart diff --git a/lib/features/favorites/data/datasources/supabase_favorites_data_source.dart b/app/lib/features/favorites/data/datasources/supabase_favorites_data_source.dart similarity index 100% rename from lib/features/favorites/data/datasources/supabase_favorites_data_source.dart rename to app/lib/features/favorites/data/datasources/supabase_favorites_data_source.dart diff --git a/lib/features/favorites/data/models/favorite_model.dart b/app/lib/features/favorites/data/models/favorite_model.dart similarity index 100% rename from lib/features/favorites/data/models/favorite_model.dart rename to app/lib/features/favorites/data/models/favorite_model.dart diff --git a/lib/features/favorites/data/repositories/favorites_repository_impl.dart b/app/lib/features/favorites/data/repositories/favorites_repository_impl.dart similarity index 100% rename from lib/features/favorites/data/repositories/favorites_repository_impl.dart rename to app/lib/features/favorites/data/repositories/favorites_repository_impl.dart diff --git a/lib/features/favorites/domain/entities/favorite.dart b/app/lib/features/favorites/domain/entities/favorite.dart similarity index 100% rename from lib/features/favorites/domain/entities/favorite.dart rename to app/lib/features/favorites/domain/entities/favorite.dart diff --git a/lib/features/favorites/domain/repositories/favorites_repository.dart b/app/lib/features/favorites/domain/repositories/favorites_repository.dart similarity index 100% rename from lib/features/favorites/domain/repositories/favorites_repository.dart rename to app/lib/features/favorites/domain/repositories/favorites_repository.dart diff --git a/lib/features/favorites/domain/usecases/get_favorites_usecase.dart b/app/lib/features/favorites/domain/usecases/get_favorites_usecase.dart similarity index 100% rename from lib/features/favorites/domain/usecases/get_favorites_usecase.dart rename to app/lib/features/favorites/domain/usecases/get_favorites_usecase.dart diff --git a/lib/features/favorites/domain/usecases/is_favorite_usecase.dart b/app/lib/features/favorites/domain/usecases/is_favorite_usecase.dart similarity index 100% rename from lib/features/favorites/domain/usecases/is_favorite_usecase.dart rename to app/lib/features/favorites/domain/usecases/is_favorite_usecase.dart diff --git a/lib/features/favorites/domain/usecases/toggle_favorite_usecase.dart b/app/lib/features/favorites/domain/usecases/toggle_favorite_usecase.dart similarity index 100% rename from lib/features/favorites/domain/usecases/toggle_favorite_usecase.dart rename to app/lib/features/favorites/domain/usecases/toggle_favorite_usecase.dart diff --git a/lib/features/favorites/presentation/screens/favorites_screen.dart b/app/lib/features/favorites/presentation/screens/favorites_screen.dart similarity index 100% rename from lib/features/favorites/presentation/screens/favorites_screen.dart rename to app/lib/features/favorites/presentation/screens/favorites_screen.dart diff --git a/lib/features/favorites/presentation/viewmodels/favorites_viewmodel.dart b/app/lib/features/favorites/presentation/viewmodels/favorites_viewmodel.dart similarity index 100% rename from lib/features/favorites/presentation/viewmodels/favorites_viewmodel.dart rename to app/lib/features/favorites/presentation/viewmodels/favorites_viewmodel.dart diff --git a/lib/features/favorites/presentation/widgets/pulse_heart_icon.dart b/app/lib/features/favorites/presentation/widgets/pulse_heart_icon.dart similarity index 100% rename from lib/features/favorites/presentation/widgets/pulse_heart_icon.dart rename to app/lib/features/favorites/presentation/widgets/pulse_heart_icon.dart diff --git a/lib/features/favorites/presentation/widgets/skeleton_listing_card.dart b/app/lib/features/favorites/presentation/widgets/skeleton_listing_card.dart similarity index 100% rename from lib/features/favorites/presentation/widgets/skeleton_listing_card.dart rename to app/lib/features/favorites/presentation/widgets/skeleton_listing_card.dart diff --git a/lib/features/impact/data/datasources/supabase_impact_data_source.dart b/app/lib/features/impact/data/datasources/supabase_impact_data_source.dart similarity index 100% rename from lib/features/impact/data/datasources/supabase_impact_data_source.dart rename to app/lib/features/impact/data/datasources/supabase_impact_data_source.dart diff --git a/lib/features/impact/data/models/platform_stats_model.dart b/app/lib/features/impact/data/models/platform_stats_model.dart similarity index 100% rename from lib/features/impact/data/models/platform_stats_model.dart rename to app/lib/features/impact/data/models/platform_stats_model.dart diff --git a/lib/features/impact/data/repositories/impact_repository_impl.dart b/app/lib/features/impact/data/repositories/impact_repository_impl.dart similarity index 100% rename from lib/features/impact/data/repositories/impact_repository_impl.dart rename to app/lib/features/impact/data/repositories/impact_repository_impl.dart diff --git a/lib/features/impact/domain/entities/platform_stats.dart b/app/lib/features/impact/domain/entities/platform_stats.dart similarity index 100% rename from lib/features/impact/domain/entities/platform_stats.dart rename to app/lib/features/impact/domain/entities/platform_stats.dart diff --git a/lib/features/impact/domain/repositories/impact_repository.dart b/app/lib/features/impact/domain/repositories/impact_repository.dart similarity index 100% rename from lib/features/impact/domain/repositories/impact_repository.dart rename to app/lib/features/impact/domain/repositories/impact_repository.dart diff --git a/lib/features/impact/domain/usecases/get_platform_stats_usecase.dart b/app/lib/features/impact/domain/usecases/get_platform_stats_usecase.dart similarity index 100% rename from lib/features/impact/domain/usecases/get_platform_stats_usecase.dart rename to app/lib/features/impact/domain/usecases/get_platform_stats_usecase.dart diff --git a/lib/features/impact/presentation/widgets/count_up_text.dart b/app/lib/features/impact/presentation/widgets/count_up_text.dart similarity index 100% rename from lib/features/impact/presentation/widgets/count_up_text.dart rename to app/lib/features/impact/presentation/widgets/count_up_text.dart diff --git a/lib/features/impact/presentation/widgets/impact_stats_widget.dart b/app/lib/features/impact/presentation/widgets/impact_stats_widget.dart similarity index 100% rename from lib/features/impact/presentation/widgets/impact_stats_widget.dart rename to app/lib/features/impact/presentation/widgets/impact_stats_widget.dart diff --git a/lib/features/listings/data/datasources/local_listings_datasource.dart b/app/lib/features/listings/data/datasources/local_listings_datasource.dart similarity index 100% rename from lib/features/listings/data/datasources/local_listings_datasource.dart rename to app/lib/features/listings/data/datasources/local_listings_datasource.dart diff --git a/lib/features/listings/data/datasources/supabase_listings_data_source.dart b/app/lib/features/listings/data/datasources/supabase_listings_data_source.dart similarity index 100% rename from lib/features/listings/data/datasources/supabase_listings_data_source.dart rename to app/lib/features/listings/data/datasources/supabase_listings_data_source.dart diff --git a/lib/features/listings/data/datasources/supabase_storage_data_source.dart b/app/lib/features/listings/data/datasources/supabase_storage_data_source.dart similarity index 100% rename from lib/features/listings/data/datasources/supabase_storage_data_source.dart rename to app/lib/features/listings/data/datasources/supabase_storage_data_source.dart diff --git a/lib/features/listings/data/models/listing_model.dart b/app/lib/features/listings/data/models/listing_model.dart similarity index 100% rename from lib/features/listings/data/models/listing_model.dart rename to app/lib/features/listings/data/models/listing_model.dart diff --git a/lib/features/listings/data/repositories/listing_repository_impl.dart b/app/lib/features/listings/data/repositories/listing_repository_impl.dart similarity index 100% rename from lib/features/listings/data/repositories/listing_repository_impl.dart rename to app/lib/features/listings/data/repositories/listing_repository_impl.dart diff --git a/lib/features/listings/domain/entities/book_condition.dart b/app/lib/features/listings/domain/entities/book_condition.dart similarity index 100% rename from lib/features/listings/domain/entities/book_condition.dart rename to app/lib/features/listings/domain/entities/book_condition.dart diff --git a/lib/features/listings/domain/entities/category.dart b/app/lib/features/listings/domain/entities/category.dart similarity index 100% rename from lib/features/listings/domain/entities/category.dart rename to app/lib/features/listings/domain/entities/category.dart diff --git a/lib/features/listings/domain/entities/listing.dart b/app/lib/features/listings/domain/entities/listing.dart similarity index 100% rename from lib/features/listings/domain/entities/listing.dart rename to app/lib/features/listings/domain/entities/listing.dart diff --git a/lib/features/listings/domain/repositories/listing_repository.dart b/app/lib/features/listings/domain/repositories/listing_repository.dart similarity index 100% rename from lib/features/listings/domain/repositories/listing_repository.dart rename to app/lib/features/listings/domain/repositories/listing_repository.dart diff --git a/lib/features/listings/domain/usecases/create_listing_usecase.dart b/app/lib/features/listings/domain/usecases/create_listing_usecase.dart similarity index 100% rename from lib/features/listings/domain/usecases/create_listing_usecase.dart rename to app/lib/features/listings/domain/usecases/create_listing_usecase.dart diff --git a/lib/features/listings/domain/usecases/delete_listing_usecase.dart b/app/lib/features/listings/domain/usecases/delete_listing_usecase.dart similarity index 100% rename from lib/features/listings/domain/usecases/delete_listing_usecase.dart rename to app/lib/features/listings/domain/usecases/delete_listing_usecase.dart diff --git a/lib/features/listings/domain/usecases/get_listing_details_usecase.dart b/app/lib/features/listings/domain/usecases/get_listing_details_usecase.dart similarity index 100% rename from lib/features/listings/domain/usecases/get_listing_details_usecase.dart rename to app/lib/features/listings/domain/usecases/get_listing_details_usecase.dart diff --git a/lib/features/listings/domain/usecases/get_listings_usecase.dart b/app/lib/features/listings/domain/usecases/get_listings_usecase.dart similarity index 100% rename from lib/features/listings/domain/usecases/get_listings_usecase.dart rename to app/lib/features/listings/domain/usecases/get_listings_usecase.dart diff --git a/lib/features/listings/domain/usecases/get_user_listings_usecase.dart b/app/lib/features/listings/domain/usecases/get_user_listings_usecase.dart similarity index 100% rename from lib/features/listings/domain/usecases/get_user_listings_usecase.dart rename to app/lib/features/listings/domain/usecases/get_user_listings_usecase.dart diff --git a/lib/features/listings/domain/usecases/search_listings_usecase.dart b/app/lib/features/listings/domain/usecases/search_listings_usecase.dart similarity index 100% rename from lib/features/listings/domain/usecases/search_listings_usecase.dart rename to app/lib/features/listings/domain/usecases/search_listings_usecase.dart diff --git a/lib/features/listings/domain/usecases/update_listing_usecase.dart b/app/lib/features/listings/domain/usecases/update_listing_usecase.dart similarity index 100% rename from lib/features/listings/domain/usecases/update_listing_usecase.dart rename to app/lib/features/listings/domain/usecases/update_listing_usecase.dart diff --git a/lib/features/listings/presentation/screens/about_screen.dart b/app/lib/features/listings/presentation/screens/about_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/about_screen.dart rename to app/lib/features/listings/presentation/screens/about_screen.dart diff --git a/lib/features/listings/presentation/screens/categories_screen.dart b/app/lib/features/listings/presentation/screens/categories_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/categories_screen.dart rename to app/lib/features/listings/presentation/screens/categories_screen.dart diff --git a/lib/features/listings/presentation/screens/contact_us_screen.dart b/app/lib/features/listings/presentation/screens/contact_us_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/contact_us_screen.dart rename to app/lib/features/listings/presentation/screens/contact_us_screen.dart diff --git a/lib/features/listings/presentation/screens/faq_screen.dart b/app/lib/features/listings/presentation/screens/faq_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/faq_screen.dart rename to app/lib/features/listings/presentation/screens/faq_screen.dart diff --git a/lib/features/listings/presentation/screens/feedback_screen.dart b/app/lib/features/listings/presentation/screens/feedback_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/feedback_screen.dart rename to app/lib/features/listings/presentation/screens/feedback_screen.dart diff --git a/lib/features/listings/presentation/screens/home_screen.dart b/app/lib/features/listings/presentation/screens/home_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/home_screen.dart rename to app/lib/features/listings/presentation/screens/home_screen.dart diff --git a/lib/features/listings/presentation/screens/listing_details_screen.dart b/app/lib/features/listings/presentation/screens/listing_details_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/listing_details_screen.dart rename to app/lib/features/listings/presentation/screens/listing_details_screen.dart diff --git a/lib/features/listings/presentation/screens/my_books_screen.dart b/app/lib/features/listings/presentation/screens/my_books_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/my_books_screen.dart rename to app/lib/features/listings/presentation/screens/my_books_screen.dart diff --git a/lib/features/listings/presentation/screens/privacy_policy_screen.dart b/app/lib/features/listings/presentation/screens/privacy_policy_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/privacy_policy_screen.dart rename to app/lib/features/listings/presentation/screens/privacy_policy_screen.dart diff --git a/lib/features/listings/presentation/screens/profile_screen.dart b/app/lib/features/listings/presentation/screens/profile_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/profile_screen.dart rename to app/lib/features/listings/presentation/screens/profile_screen.dart diff --git a/lib/features/listings/presentation/screens/search_screen.dart b/app/lib/features/listings/presentation/screens/search_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/search_screen.dart rename to app/lib/features/listings/presentation/screens/search_screen.dart diff --git a/lib/features/listings/presentation/screens/sell_screen.dart b/app/lib/features/listings/presentation/screens/sell_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/sell_screen.dart rename to app/lib/features/listings/presentation/screens/sell_screen.dart diff --git a/lib/features/listings/presentation/screens/seller_profile_screen.dart b/app/lib/features/listings/presentation/screens/seller_profile_screen.dart similarity index 100% rename from lib/features/listings/presentation/screens/seller_profile_screen.dart rename to app/lib/features/listings/presentation/screens/seller_profile_screen.dart diff --git a/lib/features/listings/presentation/viewmodels/home_viewmodel.dart b/app/lib/features/listings/presentation/viewmodels/home_viewmodel.dart similarity index 100% rename from lib/features/listings/presentation/viewmodels/home_viewmodel.dart rename to app/lib/features/listings/presentation/viewmodels/home_viewmodel.dart diff --git a/lib/features/listings/presentation/viewmodels/listing_details_viewmodel.dart b/app/lib/features/listings/presentation/viewmodels/listing_details_viewmodel.dart similarity index 100% rename from lib/features/listings/presentation/viewmodels/listing_details_viewmodel.dart rename to app/lib/features/listings/presentation/viewmodels/listing_details_viewmodel.dart diff --git a/lib/features/listings/presentation/viewmodels/locale_viewmodel.dart b/app/lib/features/listings/presentation/viewmodels/locale_viewmodel.dart similarity index 100% rename from lib/features/listings/presentation/viewmodels/locale_viewmodel.dart rename to app/lib/features/listings/presentation/viewmodels/locale_viewmodel.dart diff --git a/lib/features/listings/presentation/viewmodels/location_viewmodel.dart b/app/lib/features/listings/presentation/viewmodels/location_viewmodel.dart similarity index 100% rename from lib/features/listings/presentation/viewmodels/location_viewmodel.dart rename to app/lib/features/listings/presentation/viewmodels/location_viewmodel.dart diff --git a/lib/features/listings/presentation/viewmodels/profile_viewmodel.dart b/app/lib/features/listings/presentation/viewmodels/profile_viewmodel.dart similarity index 100% rename from lib/features/listings/presentation/viewmodels/profile_viewmodel.dart rename to app/lib/features/listings/presentation/viewmodels/profile_viewmodel.dart diff --git a/lib/features/listings/presentation/viewmodels/search_viewmodel.dart b/app/lib/features/listings/presentation/viewmodels/search_viewmodel.dart similarity index 100% rename from lib/features/listings/presentation/viewmodels/search_viewmodel.dart rename to app/lib/features/listings/presentation/viewmodels/search_viewmodel.dart diff --git a/lib/features/listings/presentation/viewmodels/sell_viewmodel.dart b/app/lib/features/listings/presentation/viewmodels/sell_viewmodel.dart similarity index 100% rename from lib/features/listings/presentation/viewmodels/sell_viewmodel.dart rename to app/lib/features/listings/presentation/viewmodels/sell_viewmodel.dart diff --git a/lib/features/listings/presentation/viewmodels/seller_profile_viewmodel.dart b/app/lib/features/listings/presentation/viewmodels/seller_profile_viewmodel.dart similarity index 100% rename from lib/features/listings/presentation/viewmodels/seller_profile_viewmodel.dart rename to app/lib/features/listings/presentation/viewmodels/seller_profile_viewmodel.dart diff --git a/lib/features/listings/presentation/widgets/listing_card.dart b/app/lib/features/listings/presentation/widgets/listing_card.dart similarity index 100% rename from lib/features/listings/presentation/widgets/listing_card.dart rename to app/lib/features/listings/presentation/widgets/listing_card.dart diff --git a/lib/features/notifications/data/datasources/supabase_notifications_data_source.dart b/app/lib/features/notifications/data/datasources/supabase_notifications_data_source.dart similarity index 100% rename from lib/features/notifications/data/datasources/supabase_notifications_data_source.dart rename to app/lib/features/notifications/data/datasources/supabase_notifications_data_source.dart diff --git a/lib/features/notifications/data/models/notification_model.dart b/app/lib/features/notifications/data/models/notification_model.dart similarity index 100% rename from lib/features/notifications/data/models/notification_model.dart rename to app/lib/features/notifications/data/models/notification_model.dart diff --git a/lib/features/notifications/data/repositories/notifications_repository_impl.dart b/app/lib/features/notifications/data/repositories/notifications_repository_impl.dart similarity index 100% rename from lib/features/notifications/data/repositories/notifications_repository_impl.dart rename to app/lib/features/notifications/data/repositories/notifications_repository_impl.dart diff --git a/lib/features/notifications/data/services/push_notification_service.dart b/app/lib/features/notifications/data/services/push_notification_service.dart similarity index 100% rename from lib/features/notifications/data/services/push_notification_service.dart rename to app/lib/features/notifications/data/services/push_notification_service.dart diff --git a/lib/features/notifications/domain/entities/notification.dart b/app/lib/features/notifications/domain/entities/notification.dart similarity index 100% rename from lib/features/notifications/domain/entities/notification.dart rename to app/lib/features/notifications/domain/entities/notification.dart diff --git a/lib/features/notifications/domain/repositories/notifications_repository.dart b/app/lib/features/notifications/domain/repositories/notifications_repository.dart similarity index 100% rename from lib/features/notifications/domain/repositories/notifications_repository.dart rename to app/lib/features/notifications/domain/repositories/notifications_repository.dart diff --git a/lib/features/notifications/presentation/screens/notifications_screen.dart b/app/lib/features/notifications/presentation/screens/notifications_screen.dart similarity index 100% rename from lib/features/notifications/presentation/screens/notifications_screen.dart rename to app/lib/features/notifications/presentation/screens/notifications_screen.dart diff --git a/lib/features/notifications/presentation/viewmodels/notifications_viewmodel.dart b/app/lib/features/notifications/presentation/viewmodels/notifications_viewmodel.dart similarity index 100% rename from lib/features/notifications/presentation/viewmodels/notifications_viewmodel.dart rename to app/lib/features/notifications/presentation/viewmodels/notifications_viewmodel.dart diff --git a/lib/features/payments/data/datasources/fapshi_data_source.dart b/app/lib/features/payments/data/datasources/fapshi_data_source.dart similarity index 100% rename from lib/features/payments/data/datasources/fapshi_data_source.dart rename to app/lib/features/payments/data/datasources/fapshi_data_source.dart diff --git a/lib/features/payments/data/repositories/payment_repository_impl.dart b/app/lib/features/payments/data/repositories/payment_repository_impl.dart similarity index 100% rename from lib/features/payments/data/repositories/payment_repository_impl.dart rename to app/lib/features/payments/data/repositories/payment_repository_impl.dart diff --git a/lib/features/payments/domain/repositories/payment_repository.dart b/app/lib/features/payments/domain/repositories/payment_repository.dart similarity index 100% rename from lib/features/payments/domain/repositories/payment_repository.dart rename to app/lib/features/payments/domain/repositories/payment_repository.dart diff --git a/lib/features/payments/domain/usecases/collect_payment_usecase.dart b/app/lib/features/payments/domain/usecases/collect_payment_usecase.dart similarity index 100% rename from lib/features/payments/domain/usecases/collect_payment_usecase.dart rename to app/lib/features/payments/domain/usecases/collect_payment_usecase.dart diff --git a/lib/features/payments/domain/usecases/get_payment_status_usecase.dart b/app/lib/features/payments/domain/usecases/get_payment_status_usecase.dart similarity index 100% rename from lib/features/payments/domain/usecases/get_payment_status_usecase.dart rename to app/lib/features/payments/domain/usecases/get_payment_status_usecase.dart diff --git a/lib/features/payments/presentation/viewmodels/payment_viewmodel.dart b/app/lib/features/payments/presentation/viewmodels/payment_viewmodel.dart similarity index 100% rename from lib/features/payments/presentation/viewmodels/payment_viewmodel.dart rename to app/lib/features/payments/presentation/viewmodels/payment_viewmodel.dart diff --git a/lib/features/payments/presentation/widgets/payment_bottom_sheet.dart b/app/lib/features/payments/presentation/widgets/payment_bottom_sheet.dart similarity index 100% rename from lib/features/payments/presentation/widgets/payment_bottom_sheet.dart rename to app/lib/features/payments/presentation/widgets/payment_bottom_sheet.dart diff --git a/lib/features/reviews/data/datasources/supabase_reviews_data_source.dart b/app/lib/features/reviews/data/datasources/supabase_reviews_data_source.dart similarity index 100% rename from lib/features/reviews/data/datasources/supabase_reviews_data_source.dart rename to app/lib/features/reviews/data/datasources/supabase_reviews_data_source.dart diff --git a/lib/features/reviews/data/repositories/review_repository_impl.dart b/app/lib/features/reviews/data/repositories/review_repository_impl.dart similarity index 100% rename from lib/features/reviews/data/repositories/review_repository_impl.dart rename to app/lib/features/reviews/data/repositories/review_repository_impl.dart diff --git a/lib/features/reviews/domain/entities/review_entity.dart b/app/lib/features/reviews/domain/entities/review_entity.dart similarity index 100% rename from lib/features/reviews/domain/entities/review_entity.dart rename to app/lib/features/reviews/domain/entities/review_entity.dart diff --git a/lib/features/reviews/domain/repositories/review_repository.dart b/app/lib/features/reviews/domain/repositories/review_repository.dart similarity index 100% rename from lib/features/reviews/domain/repositories/review_repository.dart rename to app/lib/features/reviews/domain/repositories/review_repository.dart diff --git a/lib/features/reviews/domain/usecases/create_review_usecase.dart b/app/lib/features/reviews/domain/usecases/create_review_usecase.dart similarity index 100% rename from lib/features/reviews/domain/usecases/create_review_usecase.dart rename to app/lib/features/reviews/domain/usecases/create_review_usecase.dart diff --git a/lib/features/reviews/domain/usecases/get_user_reviews_usecase.dart b/app/lib/features/reviews/domain/usecases/get_user_reviews_usecase.dart similarity index 100% rename from lib/features/reviews/domain/usecases/get_user_reviews_usecase.dart rename to app/lib/features/reviews/domain/usecases/get_user_reviews_usecase.dart diff --git a/lib/features/reviews/domain/usecases/has_reviewed_usecase.dart b/app/lib/features/reviews/domain/usecases/has_reviewed_usecase.dart similarity index 100% rename from lib/features/reviews/domain/usecases/has_reviewed_usecase.dart rename to app/lib/features/reviews/domain/usecases/has_reviewed_usecase.dart diff --git a/lib/features/reviews/presentation/viewmodels/review_viewmodel.dart b/app/lib/features/reviews/presentation/viewmodels/review_viewmodel.dart similarity index 100% rename from lib/features/reviews/presentation/viewmodels/review_viewmodel.dart rename to app/lib/features/reviews/presentation/viewmodels/review_viewmodel.dart diff --git a/lib/features/reviews/presentation/widgets/review_dialog.dart b/app/lib/features/reviews/presentation/widgets/review_dialog.dart similarity index 100% rename from lib/features/reviews/presentation/widgets/review_dialog.dart rename to app/lib/features/reviews/presentation/widgets/review_dialog.dart diff --git a/lib/features/reviews/presentation/widgets/seller_rating_badge.dart b/app/lib/features/reviews/presentation/widgets/seller_rating_badge.dart similarity index 100% rename from lib/features/reviews/presentation/widgets/seller_rating_badge.dart rename to app/lib/features/reviews/presentation/widgets/seller_rating_badge.dart diff --git a/lib/features/reviews/presentation/widgets/seller_trust_card.dart b/app/lib/features/reviews/presentation/widgets/seller_trust_card.dart similarity index 100% rename from lib/features/reviews/presentation/widgets/seller_trust_card.dart rename to app/lib/features/reviews/presentation/widgets/seller_trust_card.dart diff --git a/lib/features/reviews/presentation/widgets/star_rating_display.dart b/app/lib/features/reviews/presentation/widgets/star_rating_display.dart similarity index 100% rename from lib/features/reviews/presentation/widgets/star_rating_display.dart rename to app/lib/features/reviews/presentation/widgets/star_rating_display.dart diff --git a/lib/features/safety/data/datasources/safety_remote_datasource.dart b/app/lib/features/safety/data/datasources/safety_remote_datasource.dart similarity index 100% rename from lib/features/safety/data/datasources/safety_remote_datasource.dart rename to app/lib/features/safety/data/datasources/safety_remote_datasource.dart diff --git a/lib/features/safety/data/models/campus_zone_model.dart b/app/lib/features/safety/data/models/campus_zone_model.dart similarity index 100% rename from lib/features/safety/data/models/campus_zone_model.dart rename to app/lib/features/safety/data/models/campus_zone_model.dart diff --git a/lib/features/safety/data/repositories/safety_repository_impl.dart b/app/lib/features/safety/data/repositories/safety_repository_impl.dart similarity index 100% rename from lib/features/safety/data/repositories/safety_repository_impl.dart rename to app/lib/features/safety/data/repositories/safety_repository_impl.dart diff --git a/lib/features/safety/domain/entities/campus_zone.dart b/app/lib/features/safety/domain/entities/campus_zone.dart similarity index 100% rename from lib/features/safety/domain/entities/campus_zone.dart rename to app/lib/features/safety/domain/entities/campus_zone.dart diff --git a/lib/features/safety/domain/repositories/safety_repository.dart b/app/lib/features/safety/domain/repositories/safety_repository.dart similarity index 100% rename from lib/features/safety/domain/repositories/safety_repository.dart rename to app/lib/features/safety/domain/repositories/safety_repository.dart diff --git a/lib/features/safety/domain/usecases/get_campus_zones_usecase.dart b/app/lib/features/safety/domain/usecases/get_campus_zones_usecase.dart similarity index 100% rename from lib/features/safety/domain/usecases/get_campus_zones_usecase.dart rename to app/lib/features/safety/domain/usecases/get_campus_zones_usecase.dart diff --git a/lib/features/safety/presentation/screens/safety_guidelines_screen.dart b/app/lib/features/safety/presentation/screens/safety_guidelines_screen.dart similarity index 100% rename from lib/features/safety/presentation/screens/safety_guidelines_screen.dart rename to app/lib/features/safety/presentation/screens/safety_guidelines_screen.dart diff --git a/lib/features/safety/presentation/viewmodels/safety_viewmodel.dart b/app/lib/features/safety/presentation/viewmodels/safety_viewmodel.dart similarity index 100% rename from lib/features/safety/presentation/viewmodels/safety_viewmodel.dart rename to app/lib/features/safety/presentation/viewmodels/safety_viewmodel.dart diff --git a/lib/features/safety/presentation/widgets/meetup_tips_card.dart b/app/lib/features/safety/presentation/widgets/meetup_tips_card.dart similarity index 100% rename from lib/features/safety/presentation/widgets/meetup_tips_card.dart rename to app/lib/features/safety/presentation/widgets/meetup_tips_card.dart diff --git a/lib/features/transactions/data/datasources/supabase_transactions_data_source.dart b/app/lib/features/transactions/data/datasources/supabase_transactions_data_source.dart similarity index 100% rename from lib/features/transactions/data/datasources/supabase_transactions_data_source.dart rename to app/lib/features/transactions/data/datasources/supabase_transactions_data_source.dart diff --git a/lib/features/transactions/data/repositories/transaction_repository_impl.dart b/app/lib/features/transactions/data/repositories/transaction_repository_impl.dart similarity index 100% rename from lib/features/transactions/data/repositories/transaction_repository_impl.dart rename to app/lib/features/transactions/data/repositories/transaction_repository_impl.dart diff --git a/lib/features/transactions/domain/entities/transaction_entity.dart b/app/lib/features/transactions/domain/entities/transaction_entity.dart similarity index 100% rename from lib/features/transactions/domain/entities/transaction_entity.dart rename to app/lib/features/transactions/domain/entities/transaction_entity.dart diff --git a/lib/features/transactions/domain/repositories/transaction_repository.dart b/app/lib/features/transactions/domain/repositories/transaction_repository.dart similarity index 100% rename from lib/features/transactions/domain/repositories/transaction_repository.dart rename to app/lib/features/transactions/domain/repositories/transaction_repository.dart diff --git a/lib/features/transactions/domain/usecases/get_transaction_by_external_ref_usecase.dart b/app/lib/features/transactions/domain/usecases/get_transaction_by_external_ref_usecase.dart similarity index 100% rename from lib/features/transactions/domain/usecases/get_transaction_by_external_ref_usecase.dart rename to app/lib/features/transactions/domain/usecases/get_transaction_by_external_ref_usecase.dart diff --git a/lib/features/transactions/domain/usecases/get_user_transactions_usecase.dart b/app/lib/features/transactions/domain/usecases/get_user_transactions_usecase.dart similarity index 100% rename from lib/features/transactions/domain/usecases/get_user_transactions_usecase.dart rename to app/lib/features/transactions/domain/usecases/get_user_transactions_usecase.dart diff --git a/lib/features/transactions/presentation/screens/transaction_history_screen.dart b/app/lib/features/transactions/presentation/screens/transaction_history_screen.dart similarity index 100% rename from lib/features/transactions/presentation/screens/transaction_history_screen.dart rename to app/lib/features/transactions/presentation/screens/transaction_history_screen.dart diff --git a/lib/features/transactions/presentation/viewmodels/transaction_history_viewmodel.dart b/app/lib/features/transactions/presentation/viewmodels/transaction_history_viewmodel.dart similarity index 100% rename from lib/features/transactions/presentation/viewmodels/transaction_history_viewmodel.dart rename to app/lib/features/transactions/presentation/viewmodels/transaction_history_viewmodel.dart diff --git a/lib/firebase_options.dart b/app/lib/firebase_options.dart similarity index 100% rename from lib/firebase_options.dart rename to app/lib/firebase_options.dart diff --git a/lib/injection_container.dart b/app/lib/injection_container.dart similarity index 100% rename from lib/injection_container.dart rename to app/lib/injection_container.dart diff --git a/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb similarity index 100% rename from lib/l10n/app_en.arb rename to app/lib/l10n/app_en.arb diff --git a/lib/l10n/app_fr.arb b/app/lib/l10n/app_fr.arb similarity index 100% rename from lib/l10n/app_fr.arb rename to app/lib/l10n/app_fr.arb diff --git a/lib/l10n/app_localizations.dart b/app/lib/l10n/app_localizations.dart similarity index 100% rename from lib/l10n/app_localizations.dart rename to app/lib/l10n/app_localizations.dart diff --git a/lib/l10n/app_localizations_en.dart b/app/lib/l10n/app_localizations_en.dart similarity index 100% rename from lib/l10n/app_localizations_en.dart rename to app/lib/l10n/app_localizations_en.dart diff --git a/lib/l10n/app_localizations_fr.dart b/app/lib/l10n/app_localizations_fr.dart similarity index 100% rename from lib/l10n/app_localizations_fr.dart rename to app/lib/l10n/app_localizations_fr.dart diff --git a/lib/main.dart b/app/lib/main.dart similarity index 100% rename from lib/main.dart rename to app/lib/main.dart diff --git a/linux/.gitignore b/app/linux/.gitignore similarity index 100% rename from linux/.gitignore rename to app/linux/.gitignore diff --git a/linux/CMakeLists.txt b/app/linux/CMakeLists.txt similarity index 100% rename from linux/CMakeLists.txt rename to app/linux/CMakeLists.txt diff --git a/linux/flutter/CMakeLists.txt b/app/linux/flutter/CMakeLists.txt similarity index 100% rename from linux/flutter/CMakeLists.txt rename to app/linux/flutter/CMakeLists.txt diff --git a/linux/flutter/generated_plugin_registrant.cc b/app/linux/flutter/generated_plugin_registrant.cc similarity index 100% rename from linux/flutter/generated_plugin_registrant.cc rename to app/linux/flutter/generated_plugin_registrant.cc diff --git a/linux/flutter/generated_plugin_registrant.h b/app/linux/flutter/generated_plugin_registrant.h similarity index 100% rename from linux/flutter/generated_plugin_registrant.h rename to app/linux/flutter/generated_plugin_registrant.h diff --git a/linux/flutter/generated_plugins.cmake b/app/linux/flutter/generated_plugins.cmake similarity index 100% rename from linux/flutter/generated_plugins.cmake rename to app/linux/flutter/generated_plugins.cmake diff --git a/linux/runner/CMakeLists.txt b/app/linux/runner/CMakeLists.txt similarity index 100% rename from linux/runner/CMakeLists.txt rename to app/linux/runner/CMakeLists.txt diff --git a/linux/runner/main.cc b/app/linux/runner/main.cc similarity index 100% rename from linux/runner/main.cc rename to app/linux/runner/main.cc diff --git a/linux/runner/my_application.cc b/app/linux/runner/my_application.cc similarity index 100% rename from linux/runner/my_application.cc rename to app/linux/runner/my_application.cc diff --git a/linux/runner/my_application.h b/app/linux/runner/my_application.h similarity index 100% rename from linux/runner/my_application.h rename to app/linux/runner/my_application.h diff --git a/macos/.gitignore b/app/macos/.gitignore similarity index 100% rename from macos/.gitignore rename to app/macos/.gitignore diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/app/macos/Flutter/Flutter-Debug.xcconfig similarity index 100% rename from macos/Flutter/Flutter-Debug.xcconfig rename to app/macos/Flutter/Flutter-Debug.xcconfig diff --git a/macos/Flutter/Flutter-Release.xcconfig b/app/macos/Flutter/Flutter-Release.xcconfig similarity index 100% rename from macos/Flutter/Flutter-Release.xcconfig rename to app/macos/Flutter/Flutter-Release.xcconfig diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/app/macos/Flutter/GeneratedPluginRegistrant.swift similarity index 100% rename from macos/Flutter/GeneratedPluginRegistrant.swift rename to app/macos/Flutter/GeneratedPluginRegistrant.swift diff --git a/macos/Runner.xcodeproj/project.pbxproj b/app/macos/Runner.xcodeproj/project.pbxproj similarity index 100% rename from macos/Runner.xcodeproj/project.pbxproj rename to app/macos/Runner.xcodeproj/project.pbxproj diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/app/macos/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from macos/Runner.xcworkspace/contents.xcworkspacedata rename to app/macos/Runner.xcworkspace/contents.xcworkspacedata diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/macos/Runner/AppDelegate.swift b/app/macos/Runner/AppDelegate.swift similarity index 100% rename from macos/Runner/AppDelegate.swift rename to app/macos/Runner/AppDelegate.swift diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png diff --git a/macos/Runner/Base.lproj/MainMenu.xib b/app/macos/Runner/Base.lproj/MainMenu.xib similarity index 100% rename from macos/Runner/Base.lproj/MainMenu.xib rename to app/macos/Runner/Base.lproj/MainMenu.xib diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/app/macos/Runner/Configs/AppInfo.xcconfig similarity index 100% rename from macos/Runner/Configs/AppInfo.xcconfig rename to app/macos/Runner/Configs/AppInfo.xcconfig diff --git a/macos/Runner/Configs/Debug.xcconfig b/app/macos/Runner/Configs/Debug.xcconfig similarity index 100% rename from macos/Runner/Configs/Debug.xcconfig rename to app/macos/Runner/Configs/Debug.xcconfig diff --git a/macos/Runner/Configs/Release.xcconfig b/app/macos/Runner/Configs/Release.xcconfig similarity index 100% rename from macos/Runner/Configs/Release.xcconfig rename to app/macos/Runner/Configs/Release.xcconfig diff --git a/macos/Runner/Configs/Warnings.xcconfig b/app/macos/Runner/Configs/Warnings.xcconfig similarity index 100% rename from macos/Runner/Configs/Warnings.xcconfig rename to app/macos/Runner/Configs/Warnings.xcconfig diff --git a/macos/Runner/DebugProfile.entitlements b/app/macos/Runner/DebugProfile.entitlements similarity index 100% rename from macos/Runner/DebugProfile.entitlements rename to app/macos/Runner/DebugProfile.entitlements diff --git a/macos/Runner/Info.plist b/app/macos/Runner/Info.plist similarity index 100% rename from macos/Runner/Info.plist rename to app/macos/Runner/Info.plist diff --git a/macos/Runner/MainFlutterWindow.swift b/app/macos/Runner/MainFlutterWindow.swift similarity index 100% rename from macos/Runner/MainFlutterWindow.swift rename to app/macos/Runner/MainFlutterWindow.swift diff --git a/macos/Runner/Release.entitlements b/app/macos/Runner/Release.entitlements similarity index 100% rename from macos/Runner/Release.entitlements rename to app/macos/Runner/Release.entitlements diff --git a/macos/RunnerTests/RunnerTests.swift b/app/macos/RunnerTests/RunnerTests.swift similarity index 100% rename from macos/RunnerTests/RunnerTests.swift rename to app/macos/RunnerTests/RunnerTests.swift diff --git a/pubspec.yaml b/app/pubspec.yaml similarity index 100% rename from pubspec.yaml rename to app/pubspec.yaml diff --git a/test/.gitkeep b/app/test/.gitkeep similarity index 100% rename from test/.gitkeep rename to app/test/.gitkeep diff --git a/test/features/chat/presentation/viewmodels/chat_viewmodel_test.dart b/app/test/features/chat/presentation/viewmodels/chat_viewmodel_test.dart similarity index 100% rename from test/features/chat/presentation/viewmodels/chat_viewmodel_test.dart rename to app/test/features/chat/presentation/viewmodels/chat_viewmodel_test.dart diff --git a/test/features/listings/presentation/screens/seller_profile_screen_test.dart b/app/test/features/listings/presentation/screens/seller_profile_screen_test.dart similarity index 100% rename from test/features/listings/presentation/screens/seller_profile_screen_test.dart rename to app/test/features/listings/presentation/screens/seller_profile_screen_test.dart diff --git a/test/features/listings/presentation/viewmodels/seller_profile_viewmodel_test.dart b/app/test/features/listings/presentation/viewmodels/seller_profile_viewmodel_test.dart similarity index 100% rename from test/features/listings/presentation/viewmodels/seller_profile_viewmodel_test.dart rename to app/test/features/listings/presentation/viewmodels/seller_profile_viewmodel_test.dart diff --git a/web/favicon.png b/app/web/favicon.png similarity index 100% rename from web/favicon.png rename to app/web/favicon.png diff --git a/web/icons/Icon-192.png b/app/web/icons/Icon-192.png similarity index 100% rename from web/icons/Icon-192.png rename to app/web/icons/Icon-192.png diff --git a/web/icons/Icon-512.png b/app/web/icons/Icon-512.png similarity index 100% rename from web/icons/Icon-512.png rename to app/web/icons/Icon-512.png diff --git a/web/icons/Icon-maskable-192.png b/app/web/icons/Icon-maskable-192.png similarity index 100% rename from web/icons/Icon-maskable-192.png rename to app/web/icons/Icon-maskable-192.png diff --git a/web/icons/Icon-maskable-512.png b/app/web/icons/Icon-maskable-512.png similarity index 100% rename from web/icons/Icon-maskable-512.png rename to app/web/icons/Icon-maskable-512.png diff --git a/web/index.html b/app/web/index.html similarity index 100% rename from web/index.html rename to app/web/index.html diff --git a/web/manifest.json b/app/web/manifest.json similarity index 100% rename from web/manifest.json rename to app/web/manifest.json diff --git a/windows/.gitignore b/app/windows/.gitignore similarity index 100% rename from windows/.gitignore rename to app/windows/.gitignore diff --git a/windows/CMakeLists.txt b/app/windows/CMakeLists.txt similarity index 100% rename from windows/CMakeLists.txt rename to app/windows/CMakeLists.txt diff --git a/windows/flutter/CMakeLists.txt b/app/windows/flutter/CMakeLists.txt similarity index 100% rename from windows/flutter/CMakeLists.txt rename to app/windows/flutter/CMakeLists.txt diff --git a/windows/flutter/generated_plugin_registrant.cc b/app/windows/flutter/generated_plugin_registrant.cc similarity index 100% rename from windows/flutter/generated_plugin_registrant.cc rename to app/windows/flutter/generated_plugin_registrant.cc diff --git a/windows/flutter/generated_plugin_registrant.h b/app/windows/flutter/generated_plugin_registrant.h similarity index 100% rename from windows/flutter/generated_plugin_registrant.h rename to app/windows/flutter/generated_plugin_registrant.h diff --git a/windows/flutter/generated_plugins.cmake b/app/windows/flutter/generated_plugins.cmake similarity index 100% rename from windows/flutter/generated_plugins.cmake rename to app/windows/flutter/generated_plugins.cmake diff --git a/windows/runner/CMakeLists.txt b/app/windows/runner/CMakeLists.txt similarity index 100% rename from windows/runner/CMakeLists.txt rename to app/windows/runner/CMakeLists.txt diff --git a/windows/runner/Runner.rc b/app/windows/runner/Runner.rc similarity index 100% rename from windows/runner/Runner.rc rename to app/windows/runner/Runner.rc diff --git a/windows/runner/flutter_window.cpp b/app/windows/runner/flutter_window.cpp similarity index 100% rename from windows/runner/flutter_window.cpp rename to app/windows/runner/flutter_window.cpp diff --git a/windows/runner/flutter_window.h b/app/windows/runner/flutter_window.h similarity index 100% rename from windows/runner/flutter_window.h rename to app/windows/runner/flutter_window.h diff --git a/windows/runner/main.cpp b/app/windows/runner/main.cpp similarity index 100% rename from windows/runner/main.cpp rename to app/windows/runner/main.cpp diff --git a/windows/runner/resource.h b/app/windows/runner/resource.h similarity index 100% rename from windows/runner/resource.h rename to app/windows/runner/resource.h diff --git a/windows/runner/resources/app_icon.ico b/app/windows/runner/resources/app_icon.ico similarity index 100% rename from windows/runner/resources/app_icon.ico rename to app/windows/runner/resources/app_icon.ico diff --git a/windows/runner/runner.exe.manifest b/app/windows/runner/runner.exe.manifest similarity index 100% rename from windows/runner/runner.exe.manifest rename to app/windows/runner/runner.exe.manifest diff --git a/windows/runner/utils.cpp b/app/windows/runner/utils.cpp similarity index 100% rename from windows/runner/utils.cpp rename to app/windows/runner/utils.cpp diff --git a/windows/runner/utils.h b/app/windows/runner/utils.h similarity index 100% rename from windows/runner/utils.h rename to app/windows/runner/utils.h diff --git a/windows/runner/win32_window.cpp b/app/windows/runner/win32_window.cpp similarity index 100% rename from windows/runner/win32_window.cpp rename to app/windows/runner/win32_window.cpp diff --git a/windows/runner/win32_window.h b/app/windows/runner/win32_window.h similarity index 100% rename from windows/runner/win32_window.h rename to app/windows/runner/win32_window.h diff --git a/backend/Cargo.toml b/backend/Cargo.toml new file mode 100644 index 0000000..2927186 --- /dev/null +++ b/backend/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "backend" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/backend/src/main.rs b/backend/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/backend/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/bookbridge-rust-core/.env.example b/bookbridge-rust-core/.env.example deleted file mode 100644 index 7aa8bd3..0000000 --- a/bookbridge-rust-core/.env.example +++ /dev/null @@ -1,10 +0,0 @@ -# PostgreSQL Connection string -# Use Supabase's Supavisor Session-Mode Pooler (Port 5432) for IPv4 compatibility on Render: -# postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres -DATABASE_URL="postgresql://postgres.jacnsvcwmhoicuuzmrmr:[YOUR_DB_PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres" - -# Shared secret key for X-Internal-Secret validation (timing-attack protected) -INTERNAL_API_SECRET="your-generate-32-byte-hex-secret-here" - -# Port to bind the server listener to (defaults to 8080 if not set) -PORT=8080 diff --git a/bookbridge-rust-core/Cargo.toml b/bookbridge-rust-core/Cargo.toml deleted file mode 100644 index c71f122..0000000 --- a/bookbridge-rust-core/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "bookbridge-rust-core" -version = "0.1.0" -edition = "2021" - -[dependencies] -axum = "0.7.5" -tokio = { version = "1.38", features = ["full"] } -sqlx = { version = "0.7.4", features = ["postgres", "runtime-tokio-rustls", "macros", "chrono", "uuid"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -reqwest = { version = "0.12", features = ["json", "rustls-tls"] } -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } -thiserror = "1.0" -subtle = "2.5" -uuid = { version = "1.8", features = ["v4", "serde"] } -chrono = { version = "0.4", features = ["serde"] } -dotenvy = "0.15" -anyhow = "1.0" -tower = { version = "0.4", features = ["util"] } diff --git a/bookbridge-rust-core/src/auth.rs b/bookbridge-rust-core/src/auth.rs deleted file mode 100644 index 583ef71..0000000 --- a/bookbridge-rust-core/src/auth.rs +++ /dev/null @@ -1,38 +0,0 @@ -use axum::{ - body::Body, - extract::State, - http::{Request, StatusCode}, - middleware::Next, - response::Response, -}; -use subtle::ConstantTimeEq; -use crate::config::AppConfig; -use std::sync::Arc; - -pub async fn require_internal_auth( - State(config): State>, - request: Request, - next: Next, -) -> Result { - let header_val = request - .headers() - .get("X-Internal-Secret") - .and_then(|h| h.to_str().ok()); - - if let Some(incoming_secret) = header_val { - let expected_secret = &config.internal_api_secret; - if constant_time_compare(incoming_secret.as_bytes(), expected_secret.as_bytes()) { - return Ok(next.run(request).await); - } - } - - tracing::warn!("Unauthorized request: missing or invalid X-Internal-Secret header"); - Err(StatusCode::UNAUTHORIZED) -} - -pub fn constant_time_compare(a: &[u8], b: &[u8]) -> bool { - let lengths_match = a.len() == b.len(); - let actual_compare = if lengths_match { b } else { a }; - let cmp = a.ct_eq(actual_compare).unwrap_u8() == 1; - lengths_match && cmp -} diff --git a/bookbridge-rust-core/src/config.rs b/bookbridge-rust-core/src/config.rs deleted file mode 100644 index cc9e152..0000000 --- a/bookbridge-rust-core/src/config.rs +++ /dev/null @@ -1,35 +0,0 @@ -#[derive(Clone, Debug)] -pub struct AppConfig { - pub database_url: String, - pub internal_api_secret: String, - pub fapshi_base_url: String, - pub port: u16, -} - -impl AppConfig { - pub fn load() -> anyhow::Result { - // Load .env file if present - let _ = dotenvy::dotenv(); - - let database_url = std::env::var("DATABASE_URL") - .map_err(|_| anyhow::anyhow!("DATABASE_URL environment variable is not set"))?; - - let internal_api_secret = std::env::var("INTERNAL_API_SECRET") - .map_err(|_| anyhow::anyhow!("INTERNAL_API_SECRET environment variable is not set"))?; - - let fapshi_base_url = std::env::var("FAPSHI_BASE_URL") - .unwrap_or_else(|_| "https://live.fapshi.com".to_string()); - - let port = std::env::var("PORT") - .ok() - .and_then(|p| p.parse().ok()) - .unwrap_or(8080); - - Ok(Self { - database_url, - internal_api_secret, - fapshi_base_url, - port, - }) - } -} diff --git a/bookbridge-rust-core/src/error.rs b/bookbridge-rust-core/src/error.rs deleted file mode 100644 index b94ece3..0000000 --- a/bookbridge-rust-core/src/error.rs +++ /dev/null @@ -1,72 +0,0 @@ -use axum::{ - http::StatusCode, - response::{IntoResponse, Response}, - Json, -}; -use serde_json::json; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum AppError { - #[error("Database error: {0}")] - Database(#[from] sqlx::Error), - - #[error("HTTP client error: {0}")] - Reqwest(#[from] reqwest::Error), - - #[error("JSON error: {0}")] - Json(#[from] serde_json::Error), - - #[error("Unauthorized: {0}")] - Unauthorized(String), - - #[error("Fapshi error: {0}")] - Fapshi(String), - - #[error("Bad Request: {0}")] - BadRequest(String), - - #[error("Internal server error: {0}")] - Internal(String), -} - -impl IntoResponse for AppError { - fn into_response(self) -> Response { - let (status, error_message) = match &self { - AppError::Database(e) => { - tracing::error!("Database error: {:?}", e); - (StatusCode::INTERNAL_SERVER_ERROR, "Database error".to_string()) - } - AppError::Reqwest(e) => { - tracing::error!("Reqwest error: {:?}", e); - (StatusCode::BAD_GATEWAY, "Gateway error".to_string()) - } - AppError::Json(e) => { - tracing::error!("JSON serialization error: {:?}", e); - (StatusCode::BAD_REQUEST, "Malformed JSON request".to_string()) - } - AppError::Unauthorized(msg) => { - tracing::warn!("Unauthorized access: {}", msg); - (StatusCode::UNAUTHORIZED, msg.clone()) - } - AppError::Fapshi(msg) => { - tracing::error!("Fapshi integration error: {}", msg); - (StatusCode::BAD_GATEWAY, msg.clone()) - } - AppError::BadRequest(msg) => { - tracing::warn!("Bad request: {}", msg); - (StatusCode::BAD_REQUEST, msg.clone()) - } - AppError::Internal(msg) => { - tracing::error!("Internal error: {}", msg); - (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()) - } - }; - - let body = Json(json!({ - "error": error_message, - })); - - (status, body).into_response() - } -} diff --git a/bookbridge-rust-core/src/fapshi.rs b/bookbridge-rust-core/src/fapshi.rs deleted file mode 100644 index 8ead206..0000000 --- a/bookbridge-rust-core/src/fapshi.rs +++ /dev/null @@ -1,284 +0,0 @@ -use crate::error::AppError; -use sqlx::PgPool; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -pub struct FapshiClient { - http: reqwest::Client, - base_url: String, -} - -#[derive(Serialize, Clone)] -pub struct PayoutPayload { - pub amount: f64, - pub phone: String, - pub name: String, - #[serde(rename = "externalId")] - pub external_id: String, - pub message: String, -} - -#[derive(Deserialize, Serialize, Debug)] -pub struct PayoutResponse { - #[serde(rename = "statusCode")] - pub status_code: u16, - #[serde(rename = "transId")] - pub trans_id: Option, - pub message: Option, -} - -#[derive(Deserialize, Serialize, Debug)] -pub struct PollResponse { - pub status: Option, - pub state: Option, - #[serde(rename = "statusCode")] - pub status_code: Option, - pub message: Option, -} - -#[derive(Deserialize, Serialize, Debug)] -pub struct FapshiSearchItem { - #[serde(rename = "transId")] - pub trans_id: String, - pub status: String, - #[serde(rename = "externalId")] - pub external_id: Option, -} - -impl FapshiClient { - pub fn new(base_url: String) -> Self { - Self { - http: reqwest::Client::new(), - base_url, - } - } - - /// Fetches a key from the `app_secrets` table. - async fn get_secret(pool: &PgPool, key: &str) -> Result { - let row: (String,) = sqlx::query_as("SELECT value FROM app_secrets WHERE key = $1") - .bind(key) - .fetch_one(pool) - .await?; - Ok(row.0) - } - - /// Clean phone number: remove non-digits and strip leading "237". - pub fn clean_phone(phone: &str) -> String { - let mut cleaned: String = phone.chars().filter(|c| c.is_ascii_digit()).collect(); - if cleaned.starts_with("237") && cleaned.len() > 3 { - cleaned = cleaned[3..].to_string(); - } - cleaned - } - - /// Get payout endpoint. - fn payout_url(&self) -> String { - if self.base_url.contains("live.fapshi.com") || self.base_url.contains("api.fapshi.com") { - "https://live.fapshi.com/payout".to_string() - } else { - format!("{}/payout", self.base_url) - } - } - - /// Get status endpoint. - fn status_url(&self, reference: &str) -> String { - if self.base_url.contains("live.fapshi.com") || self.base_url.contains("api.fapshi.com") { - format!("https://api.fapshi.com/payment-status/{}", reference) - } else { - format!("{}/payment-status/{}", self.base_url, reference) - } - } - - /// Checks if a payout has already been processed successfully on Fapshi by searching by externalId. - pub async fn check_existing_payout( - &self, - pool: &PgPool, - external_id: &str, - ) -> Result, AppError> { - let api_user = Self::get_secret(pool, "fapshi_payout_api_user").await?; - let api_key = Self::get_secret(pool, "fapshi_payout_api_key").await?; - - let endpoint = if self.base_url.contains("live.fapshi.com") || self.base_url.contains("api.fapshi.com") { - "https://live.fapshi.com/search".to_string() - } else { - format!("{}/search", self.base_url) - }; - - let response = self.http.get(&endpoint) - .header("apiuser", &api_user) - .header("apikey", &api_key) - .query(&[("externalId", external_id)]) - .send() - .await; - - match response { - Ok(res) => { - let status = res.status().as_u16(); - if status == 200 { - let items: Vec = res.json().await?; - for item in items { - if let Some(ref ext_id) = item.external_id { - if ext_id == external_id { - let status_upper = item.status.to_uppercase(); - if status_upper == "SUCCESSFUL" || status_upper == "SUCCESS" { - return Ok(Some(item.trans_id)); - } - } - } - } - Ok(None) - } else { - let body_text = res.text().await.unwrap_or_else(|_| "No body".to_string()); - Err(AppError::Fapshi(format!("Fapshi search returned status {}: {}", status, body_text))) - } - } - Err(e) => { - Err(AppError::Reqwest(e)) - } - } - } - - /// Performs payout via Fapshi and logs to fapshi_audit_logs. - #[allow(clippy::too_many_arguments)] - pub async fn execute_payout( - &self, - pool: &PgPool, - tx_id: Uuid, - amount: f64, - phone: &str, - seller_name: &str, - external_id: &str, - listing_id: Uuid, - ) -> Result { - let api_user = Self::get_secret(pool, "fapshi_payout_api_user").await?; - let api_key = Self::get_secret(pool, "fapshi_payout_api_key").await?; - - let cleaned_phone = Self::clean_phone(phone); - let request_payload = PayoutPayload { - amount, - phone: cleaned_phone, - name: seller_name.to_string(), - external_id: external_id.to_string(), - message: format!("BookBridge escrow payout for listing {}", listing_id), - }; - - let endpoint = self.payout_url(); - let req_val = serde_json::to_value(&request_payload)?; - - let response = self.http.post(&endpoint) - .header("Content-Type", "application/json") - .header("apiuser", &api_user) - .header("apikey", &api_key) - .json(&request_payload) - .send() - .await; - - let (status_code, resp_val, result) = match response { - Ok(res) => { - let status = res.status().as_u16(); - let body_res: Result = res.json().await; - match body_res { - Ok(body) => { - let val = serde_json::to_value(&body)?; - if status == 200 && body.status_code == 200 { - if let Some(trans_id) = body.trans_id { - (status, val, Ok(trans_id)) - } else { - (status, val, Err(AppError::Fapshi("Payout succeeded but transId was missing".to_string()))) - } - } else { - let msg = body.message.unwrap_or_else(|| "Unknown Fapshi payout error".to_string()); - (status, val, Err(AppError::Fapshi(format!("Fapshi payout error ({}): {}", body.status_code, msg)))) - } - } - Err(e) => { - let err_msg = format!("JSON decode error: {}", e); - (status, serde_json::json!({ "error": err_msg }), Err(AppError::Reqwest(e))) - } - } - } - Err(e) => { - let err_msg = format!("Network error: {}", e); - (500, serde_json::json!({ "error": err_msg }), Err(AppError::Reqwest(e))) - } - }; - - // Write to fapshi_audit_logs (gracefully catch errors to prevent double-payouts on db connection drops) - if let Err(e) = sqlx::query( - "INSERT INTO fapshi_audit_logs (transaction_id, endpoint, request_payload, response_payload, status_code) VALUES ($1, $2, $3, $4, $5)" - ) - .bind(tx_id) - .bind(&endpoint) - .bind(req_val) - .bind(resp_val) - .bind(status_code as i32) - .execute(pool) - .await { - tracing::error!("Failed to write to fapshi_audit_logs during payout: {:?}", e); - } - - result - } - - /// Queries Fapshi status for polling stuck transactions. - pub async fn poll_payment_status( - &self, - pool: &PgPool, - tx_id: Uuid, - reference: &str, - ) -> Result { - let api_user = Self::get_secret(pool, "fapshi_api_user").await?; - let api_key = Self::get_secret(pool, "fapshi_api_key").await?; - - let endpoint = self.status_url(reference); - - let response = self.http.get(&endpoint) - .header("apiuser", &api_user) - .header("apikey", &api_key) - .send() - .await; - - let (status_code, resp_val, result) = match response { - Ok(res) => { - let status = res.status().as_u16(); - let body_res: Result = res.json().await; - match body_res { - Ok(body) => { - let val = serde_json::to_value(&body)?; - if status == 200 { - let fapshi_status = body.status.or(body.state).unwrap_or_default(); - (status, val, Ok(fapshi_status)) - } else { - let msg = body.message.unwrap_or_else(|| "Unknown status check error".to_string()); - (status, val, Err(AppError::Fapshi(format!("Fapshi poll error ({}): {}", status, msg)))) - } - } - Err(e) => { - let err_msg = format!("JSON decode error: {}", e); - (status, serde_json::json!({ "error": err_msg }), Err(AppError::Reqwest(e))) - } - } - } - Err(e) => { - let err_msg = format!("Network error: {}", e); - (500, serde_json::json!({ "error": err_msg }), Err(AppError::Reqwest(e))) - } - }; - - // Write to fapshi_audit_logs for audit trail (gracefully log errors) - if let Err(e) = sqlx::query( - "INSERT INTO fapshi_audit_logs (transaction_id, endpoint, request_payload, response_payload, status_code) VALUES ($1, $2, $3, $4, $5)" - ) - .bind(tx_id) - .bind(&endpoint) - .bind(serde_json::Value::Null) - .bind(resp_val) - .bind(status_code as i32) - .execute(pool) - .await { - tracing::error!("Failed to write to fapshi_audit_logs during polling: {:?}", e); - } - - result - } -} diff --git a/bookbridge-rust-core/src/lib.rs b/bookbridge-rust-core/src/lib.rs deleted file mode 100644 index 6afd929..0000000 --- a/bookbridge-rust-core/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod auth; -pub mod config; -pub mod error; -pub mod fapshi; -pub mod routes; - -use std::sync::Arc; -use std::sync::Mutex; -use std::collections::HashSet; -use uuid::Uuid; -use sqlx::PgPool; - -#[derive(Clone)] -pub struct AppState { - pub pool: PgPool, - pub in_progress_payouts: Arc>>, - pub fapshi_base_url: String, -} diff --git a/bookbridge-rust-core/src/main.rs b/bookbridge-rust-core/src/main.rs deleted file mode 100644 index 0108e86..0000000 --- a/bookbridge-rust-core/src/main.rs +++ /dev/null @@ -1,69 +0,0 @@ -use axum::{ - middleware, - routing::{get, post}, - Router, -}; -use sqlx::PgPool; -use std::sync::Arc; -use tokio::net::TcpListener; - -use bookbridge_rust_core::config::AppConfig; -use bookbridge_rust_core::routes::health::health_handler; -use bookbridge_rust_core::routes::escrow::{process_releases_handler, poll_pending_handler}; -use bookbridge_rust_core::routes::webhook::fapshi_webhook_handler; -use bookbridge_rust_core::auth::require_internal_auth; -use bookbridge_rust_core::AppState; - -#[tokio::main] -async fn main() -> Result<(), Box> { - // Initialize tracing subscriber - let _ = tracing_subscriber::fmt() - .with_env_filter( - std::env::var("RUST_LOG") - .unwrap_or_else(|_| "info,bookbridge_rust_core=debug".into()), - ) - .try_init(); - - tracing::info!("Initializing bookbridge-rust-core on Render..."); - - // 1. Load config - let config = AppConfig::load()?; - let shared_config = Arc::new(config.clone()); - - // 2. Setup database connection pool - let pool = PgPool::connect(&config.database_url).await?; - - - - // 3. Setup AppState - let state = AppState { - pool, - in_progress_payouts: Arc::new(std::sync::Mutex::new(std::collections::HashSet::new())), - fapshi_base_url: config.fapshi_base_url, - }; - - // 4. Build authenticated routes - let internal_routes = Router::new() - .route("/escrow/process-releases", post(process_releases_handler)) - .route("/escrow/poll-pending", post(poll_pending_handler)) - .layer(middleware::from_fn_with_state( - shared_config.clone(), - require_internal_auth, - )) - .with_state(state.clone()); - - // 5. Main router (health and webhooks are public / custom authenticated) - let app = Router::new() - .route("/health", get(health_handler)) - .route("/webhooks/fapshi", post(fapshi_webhook_handler)) - .nest("/internal", internal_routes) - .with_state(state); - - // 6. Run Axum server using standard TcpListener - let addr = format!("0.0.0.0:{}", config.port); - tracing::info!("Starting Axum server on {}", addr); - let listener = TcpListener::bind(&addr).await?; - axum::serve(listener, app).await?; - - Ok(()) -} diff --git a/bookbridge-rust-core/src/routes/escrow.rs b/bookbridge-rust-core/src/routes/escrow.rs deleted file mode 100644 index c1eb786..0000000 --- a/bookbridge-rust-core/src/routes/escrow.rs +++ /dev/null @@ -1,392 +0,0 @@ -use axum::{extract::State, Json, response::IntoResponse}; -use serde::Serialize; -use crate::error::AppError; -use crate::fapshi::FapshiClient; -use crate::AppState; -use sqlx::Row; -use sqlx::PgConnection; -use uuid::Uuid; -use chrono::Utc; - -#[derive(Serialize)] -pub struct ProcessReleasesResponse { - pub processed: usize, - pub released: usize, - pub failed: usize, - pub results: Vec, -} - -#[derive(Serialize)] -pub struct ReleaseResult { - pub transaction_id: Uuid, - pub ok: bool, - pub error: Option, -} - -#[derive(Serialize)] -pub struct PollPendingResponse { - pub processed: usize, - pub results: Vec, -} - -#[derive(Serialize)] -pub struct PollResult { - pub id: Uuid, - pub reference: String, - pub status: String, - pub error: Option, -} - -/// Shared helper function to process all database side effects for a successful book purchase. -/// This includes marking the listing as sold, setting the transaction to 'held', upserting the escrow row, -/// and creating the initial buyer/seller chat message. -pub async fn handle_purchase_success_db( - conn: &mut PgConnection, - listing_id: Uuid, - buyer_id: Uuid, - seller_id: Uuid, - tx_id: Uuid, - now: chrono::DateTime, -) -> Result<(), AppError> { - // 1. Update listing status to 'sold' - sqlx::query("UPDATE listings SET status = 'sold' WHERE id = $1") - .bind(listing_id) - .execute(&mut *conn) - .await?; - - // 2. Update transaction status to 'held' - sqlx::query("UPDATE transactions SET status = 'held' WHERE id = $1") - .bind(tx_id) - .execute(&mut *conn) - .await?; - - // 3. Upsert escrow transaction atomically - sqlx::query( - "INSERT INTO escrow_transactions (transaction_id, status, created_at, updated_at) \ - VALUES ($1, 'held', $2, $2) \ - ON CONFLICT (transaction_id) DO UPDATE SET status = 'held', updated_at = $2" - ) - .bind(tx_id) - .bind(now) - .execute(&mut *conn) - .await?; - - // 4. Insert automated buyer/seller chat message - sqlx::query( - "INSERT INTO messages (listing_id, sender_id, receiver_id, content, is_read, created_at) \ - VALUES ($1, $2, $3, $4, false, $5)" - ) - .bind(listing_id) - .bind(buyer_id) - .bind(seller_id) - .bind("Hello! I just purchased this book via BookBridge. When can we meet to complete the exchange?") - .bind(now) - .execute(&mut *conn) - .await?; - - Ok(()) -} - -pub async fn release_escrow( - state: &AppState, - tx_id: Uuid, -) -> Result<(), AppError> { - // 1. Claim in-progress lock to mitigate concurrent execution / double payout risk - { - let mut in_progress = state.in_progress_payouts.lock().map_err(|_| { - AppError::Internal("Failed to acquire in-progress lock".to_string()) - })?; - if in_progress.contains(&tx_id) { - return Err(AppError::BadRequest(format!("Payout for transaction {} is already in progress", tx_id))); - } - in_progress.insert(tx_id); - } - - // Ensure we release lock on exit - struct LockGuard<'a> { - tx_id: Uuid, - in_progress: &'a std::sync::Mutex>, - } - impl<'a> Drop for LockGuard<'a> { - fn drop(&mut self) { - if let Ok(mut lock) = self.in_progress.lock() { - lock.remove(&self.tx_id); - } - } - } - let _guard = LockGuard { - tx_id, - in_progress: &state.in_progress_payouts, - }; - - let fapshi = FapshiClient::new(state.fapshi_base_url.clone()); - - // 2. Fetch transaction and escrow status to ensure both are in 'held' status - let tx_row = sqlx::query( - "SELECT t.listing_id, t.seller_id, t.amount, t.commission_amount, t.payment_reference, \ - t.status as tx_status, e.status as escrow_status \ - FROM transactions t \ - JOIN escrow_transactions e ON t.id = e.transaction_id \ - WHERE t.id = $1" - ) - .bind(tx_id) - .fetch_optional(&state.pool) - .await?; - - let tx = match tx_row { - Some(row) => { - let tx_status: String = row.get("tx_status"); - let escrow_status: String = row.get("escrow_status"); - if tx_status != "held" || escrow_status != "held" { - return Err(AppError::BadRequest(format!( - "Transaction or Escrow {} is not in 'held' status (tx: {}, escrow: {})", - tx_id, tx_status, escrow_status - ))); - } - row - } - None => return Err(AppError::BadRequest(format!("Transaction {} not found", tx_id))), - }; - - let listing_id: Uuid = tx.get("listing_id"); - let seller_id: Uuid = tx.get("seller_id"); - let amount: f64 = tx.get("amount"); - let commission_amount: Option = tx.get("commission_amount"); - let payment_reference: String = tx.get("payment_reference"); - - // 3. Fetch seller profile - let seller_row = sqlx::query( - "SELECT whatsapp_number, full_name FROM profiles WHERE id = $1" - ) - .bind(seller_id) - .fetch_optional(&state.pool) - .await?; - - let seller = match seller_row { - Some(row) => row, - None => return Err(AppError::BadRequest(format!("Seller profile {} not found", seller_id))), - }; - - let whatsapp_number: Option = seller.get("whatsapp_number"); - let full_name: Option = seller.get("full_name"); - - let phone = match whatsapp_number { - Some(num) if !num.trim().is_empty() => num, - _ => return Err(AppError::BadRequest("Seller has no payout number configured".to_string())), - }; - - let payout_amount = amount - commission_amount.unwrap_or(0.0); - let external_id = format!("escrow_payout_{}", payment_reference); - let seller_name_str = full_name.unwrap_or_else(|| "BookBridge Seller".to_string()); - - // Check if payout was already executed successfully on Fapshi in a previous run - let mut trans_id = match fapshi.check_existing_payout(&state.pool, &external_id).await { - Ok(Some(tid)) => { - tracing::info!("Payout for transaction {} already completed on Fapshi (transId: {}). Skipping payout call.", tx_id, tid); - Some(tid) - } - Ok(None) => None, // Safe to proceed with payout - Err(e) => { - tracing::error!("Could not verify prior payout status for tx {}: {:?}. Aborting to prevent potential double-payout.", tx_id, e); - return Err(e); // Fail closed - let the next cron run retry - } - }; - - // If not already processed, execute payout - if trans_id.is_none() { - let tid = fapshi.execute_payout( - &state.pool, - tx_id, - payout_amount, - &phone, - &seller_name_str, - &external_id, - listing_id, - ) - .await?; - trans_id = Some(tid); - } - - let trans_id_str = trans_id.unwrap_or_default(); - - // 5. Update databases only after payout is verified successful - let now = Utc::now(); - let mut transaction = state.pool.begin().await?; - - sqlx::query( - "UPDATE escrow_transactions SET status = 'released', updated_at = $1 \ - WHERE transaction_id = $2 AND status = 'held'" - ) - .bind(now) - .bind(tx_id) - .execute(&mut *transaction) - .await?; - - sqlx::query( - "UPDATE transactions SET status = 'successful', payout_status = 'successful', payout_reference = $1 \ - WHERE id = $2" - ) - .bind(&trans_id_str) - .bind(tx_id) - .execute(&mut *transaction) - .await?; - - transaction.commit().await?; - - Ok(()) -} - -pub async fn process_releases_handler( - State(state): State, -) -> Result { - let now = Utc::now(); - - // Find all held escrows whose release_deadline has passed - let expired_rows = sqlx::query( - "SELECT transaction_id FROM escrow_transactions \ - WHERE status = 'held' AND release_deadline <= $1" - ) - .bind(now) - .fetch_all(&state.pool) - .await?; - - let mut results = Vec::new(); - let mut released_count = 0; - let mut failed_count = 0; - - for row in expired_rows { - let tx_id: Uuid = row.get("transaction_id"); - match release_escrow(&state, tx_id).await { - Ok(_) => { - released_count += 1; - results.push(ReleaseResult { - transaction_id: tx_id, - ok: true, - error: None, - }); - } - Err(e) => { - failed_count += 1; - let err_str = e.to_string(); - tracing::error!("Failed to auto-release escrow {}: {}", tx_id, err_str); - results.push(ReleaseResult { - transaction_id: tx_id, - ok: false, - error: Some(err_str), - }); - } - } - } - - Ok(Json(ProcessReleasesResponse { - processed: results.len(), - released: released_count, - failed: failed_count, - results, - })) -} - -pub async fn poll_pending_handler( - State(state): State, -) -> Result { - let fapshi = FapshiClient::new(state.fapshi_base_url.clone()); - - // Find all transactions stuck in pending_payment for more than 10 minutes - let ten_minutes_ago = Utc::now() - chrono::Duration::minutes(10); - - let txs = sqlx::query( - "SELECT id, payment_reference, listing_id, buyer_id, seller_id, amount \ - FROM transactions \ - WHERE status = 'pending_payment' AND created_at <= $1" - ) - .bind(ten_minutes_ago) - .fetch_all(&state.pool) - .await?; - - let mut results = Vec::new(); - - for row in txs { - let tx_id: Uuid = row.get("id"); - let reference: String = row.get("payment_reference"); - let listing_id: Uuid = row.get("listing_id"); - let buyer_id: Uuid = row.get("buyer_id"); - let seller_id: Uuid = row.get("seller_id"); - - tracing::info!("Checking Fapshi status for transaction ref: {}", reference); - - match fapshi.poll_payment_status(&state.pool, tx_id, &reference).await { - Ok(fapshi_status) => { - let status_upper = fapshi_status.to_uppercase(); - if status_upper == "SUCCESSFUL" || status_upper == "SUCCESS" { - // Process successful payment - let now = Utc::now(); - let mut transaction = state.pool.begin().await?; - - if let Err(e) = handle_purchase_success_db( - &mut transaction, - listing_id, - buyer_id, - seller_id, - tx_id, - now, - ).await { - tracing::error!("Error writing successful purchase updates to DB during poll: {:?}", e); - transaction.rollback().await?; - results.push(PollResult { - id: tx_id, - reference: reference.clone(), - status: "error".to_string(), - error: Some(e.to_string()), - }); - continue; - } - - transaction.commit().await?; - - results.push(PollResult { - id: tx_id, - reference: reference.clone(), - status: "held".to_string(), - error: None, - }); - } else if status_upper == "FAILED" || status_upper == "EXPIRED" { - // Mark transaction as failed - sqlx::query("UPDATE transactions SET status = 'failed' WHERE id = $1") - .bind(tx_id) - .execute(&state.pool) - .await?; - - results.push(PollResult { - id: tx_id, - reference: reference.clone(), - status: "failed".to_string(), - error: None, - }); - } else { - // Still pending/created - results.push(PollResult { - id: tx_id, - reference: reference.clone(), - status: fapshi_status.clone(), - error: None, - }); - } - } - Err(e) => { - let err_str = e.to_string(); - tracing::error!("Error polling transaction status for {}: {}", reference, err_str); - results.push(PollResult { - id: tx_id, - reference: reference.clone(), - status: "error".to_string(), - error: Some(err_str), - }); - } - } - } - - Ok(Json(PollPendingResponse { - processed: results.len(), - results, - })) -} diff --git a/bookbridge-rust-core/src/routes/health.rs b/bookbridge-rust-core/src/routes/health.rs deleted file mode 100644 index 2858b7b..0000000 --- a/bookbridge-rust-core/src/routes/health.rs +++ /dev/null @@ -1,6 +0,0 @@ -use axum::{response::IntoResponse, Json}; -use serde_json::json; - -pub async fn health_handler() -> impl IntoResponse { - Json(json!({ "status": "ok" })) -} diff --git a/bookbridge-rust-core/src/routes/mod.rs b/bookbridge-rust-core/src/routes/mod.rs deleted file mode 100644 index 8ac07fe..0000000 --- a/bookbridge-rust-core/src/routes/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod escrow; -pub mod health; -pub mod webhook; diff --git a/bookbridge-rust-core/src/routes/webhook.rs b/bookbridge-rust-core/src/routes/webhook.rs deleted file mode 100644 index a8b440f..0000000 --- a/bookbridge-rust-core/src/routes/webhook.rs +++ /dev/null @@ -1,372 +0,0 @@ -use axum::{extract::State, http::HeaderMap, response::IntoResponse, Json}; -use serde::{Deserialize, Serialize}; -use crate::error::AppError; -use crate::auth::constant_time_compare; -use crate::routes::escrow::handle_purchase_success_db; -use crate::AppState; -use sqlx::{PgPool, Row}; -use uuid::Uuid; -use chrono::Utc; - -#[derive(Deserialize, Serialize, Debug)] -pub struct FapshiWebhookPayload { - pub status: Option, - pub state: Option, - #[serde(rename = "transId")] - pub trans_id: Option, - #[serde(rename = "transactionId")] - pub transaction_id: Option, - pub id: Option, - pub amount: Option, - #[serde(rename = "externalId")] - pub external_id: Option, - #[serde(rename = "externalReference")] - pub external_reference: Option, - pub custom: Option, -} - -async fn verify_webhook_auth(pool: &PgPool, headers: &HeaderMap) -> Result<(), AppError> { - // A. Check x-wh-secret header (dashboard verification key) - if let Some(wh_secret_header) = headers.get("x-wh-secret").and_then(|h| h.to_str().ok()) { - let secret_row: Option<(String,)> = sqlx::query_as("SELECT value FROM app_secrets WHERE key = 'fapshi_webhook_secret'") - .fetch_optional(pool) - .await?; - - if let Some(row) = secret_row { - if constant_time_compare(wh_secret_header.as_bytes(), row.0.as_bytes()) { - return Ok(()); - } - } - } - - - - - - let mut headers_debug = std::collections::HashMap::new(); - for (k, v) in headers.iter() { - if let Ok(val) = v.to_str() { - // Mask the actual sensitive values but show prefix/length for verification - let masked = if val.len() > 8 { - format!("{}... (len: {})", &val[..8], val.len()) - } else { - "***".to_string() - }; - headers_debug.insert(k.as_str().to_string(), masked); - } - } - tracing::warn!("Unauthorized webhook request: invalid credentials or headers. Received headers: {:?}", headers_debug); - Err(AppError::Unauthorized("Invalid authentication credentials".to_string())) -} - -fn parse_purchase_ref(external_ref: &str) -> Result<(Uuid, Uuid), AppError> { - let separator = if external_ref.contains(':') { ':' } else { '_' }; - let parts: Vec<&str> = external_ref.split(separator).collect(); - if parts.len() < 3 { - return Err(AppError::BadRequest("Malformed external_reference for purchase".to_string())); - } - let listing_id = Uuid::parse_str(parts[1]) - .map_err(|_| AppError::BadRequest("Invalid listing_id UUID".to_string()))?; - let buyer_id = Uuid::parse_str(parts[2]) - .map_err(|_| AppError::BadRequest("Invalid buyer_id UUID".to_string()))?; - Ok((listing_id, buyer_id)) -} - -fn parse_boost_ref(external_ref: &str) -> Result<(Uuid, i32), AppError> { - let separator = if external_ref.contains(':') { ':' } else { '_' }; - let parts: Vec<&str> = external_ref.split(separator).collect(); - if parts.len() < 2 { - return Err(AppError::BadRequest("Malformed external_reference for boost".to_string())); - } - let listing_id = Uuid::parse_str(parts[1]) - .map_err(|_| AppError::BadRequest("Invalid listing_id UUID".to_string()))?; - let duration = if parts.len() >= 3 { - parts[2].parse::().unwrap_or(7) - } else { - 7 - }; - Ok((listing_id, duration)) -} - -fn parse_donation_ref(external_ref: &str) -> Result, AppError> { - let separator = if external_ref.contains(':') { ':' } else { '_' }; - let parts: Vec<&str> = external_ref.split(separator).collect(); - if parts.len() < 2 { - return Err(AppError::BadRequest("Malformed external_reference for donation".to_string())); - } - let user_id_str = parts[1]; - if user_id_str == "anonymous" { - Ok(None) - } else { - let uid = Uuid::parse_str(user_id_str) - .map_err(|_| AppError::BadRequest("Invalid user_id UUID".to_string()))?; - Ok(Some(uid)) - } -} - -async fn handle_boost_success( - pool: &PgPool, - reference: &str, - amount: f64, - external_ref: &str, -) -> Result<(), AppError> { - let (listing_id, duration) = parse_boost_ref(external_ref)?; - - let listing_row = sqlx::query("SELECT seller_id FROM listings WHERE id = $1") - .bind(listing_id) - .fetch_optional(pool) - .await?; - - let listing = match listing_row { - Some(row) => row, - None => return Err(AppError::BadRequest(format!("Listing {} not found for boost", listing_id))), - }; - let user_id: Uuid = listing.get("seller_id"); - - let now = Utc::now(); - let rows_affected = sqlx::query( - "INSERT INTO boost_payments ( \ - payment_reference, listing_id, user_id, amount, duration_days, status, created_at \ - ) \ - VALUES ($1, $2, $3, $4, $5, 'successful', $6) \ - ON CONFLICT (payment_reference) DO NOTHING" - ) - .bind(reference) - .bind(listing_id) - .bind(user_id) - .bind(amount) - .bind(duration) - .bind(now) - .execute(pool) - .await? - .rows_affected(); - - if rows_affected == 0 { - tracing::info!("Boost payment with reference {} already recorded. Skipping listing boost update.", reference); - return Ok(()); - } - - let expires_at = now + chrono::Duration::days(duration as i64); - sqlx::query( - "UPDATE listings SET is_boosted = true, boost_expires_at = $1 WHERE id = $2" - ) - .bind(expires_at) - .bind(listing_id) - .execute(pool) - .await?; - - Ok(()) -} - -async fn handle_donation_success( - pool: &PgPool, - reference: &str, - amount: f64, - external_ref: &str, -) -> Result<(), AppError> { - let user_id = parse_donation_ref(external_ref)?; - let now = Utc::now(); - - sqlx::query( - "INSERT INTO donations (payment_reference, user_id, amount, status, created_at) \ - VALUES ($1, $2, $3, 'successful', $4) \ - ON CONFLICT (payment_reference) DO NOTHING" - ) - .bind(reference) - .bind(user_id) - .bind(amount) - .bind(now) - .execute(pool) - .await?; - - Ok(()) -} - -async fn handle_purchase_success( - state: &AppState, - reference: &str, - amount: f64, - external_ref: &str, -) -> Result<(), AppError> { - let (listing_id, buyer_id) = parse_purchase_ref(external_ref)?; - - let listing_row = sqlx::query("SELECT seller_id FROM listings WHERE id = $1") - .bind(listing_id) - .fetch_optional(&state.pool) - .await?; - - let listing = match listing_row { - Some(row) => row, - None => return Err(AppError::BadRequest(format!("Listing {} not found for purchase", listing_id))), - }; - let seller_id: Uuid = listing.get("seller_id"); - - let payout_amount = (amount * 0.95).floor(); - let commission_amount = amount - payout_amount; - - let now = Utc::now(); - - // Atomically upsert the transaction using ON CONFLICT DO UPDATE. - // If the transaction status is already 'held' or 'successful' (completed), the DO UPDATE will fail the WHERE clause - // and return 0 rows. - let tx_row = sqlx::query( - "INSERT INTO transactions ( \ - payment_reference, listing_id, buyer_id, seller_id, amount, status, \ - payout_status, payout_reference, commission_amount, created_at \ - ) \ - VALUES ($1, $2, $3, $4, $5, 'held', 'pending', NULL, $6, $7) \ - ON CONFLICT (payment_reference) \ - DO UPDATE SET \ - status = 'held' \ - WHERE transactions.status = 'pending_payment' \ - RETURNING id" - ) - .bind(reference) - .bind(listing_id) - .bind(buyer_id) - .bind(seller_id) - .bind(amount) - .bind(commission_amount) - .bind(now) - .fetch_optional(&state.pool) - .await?; - - let tx_id = match tx_row { - Some(row) => { - let id: Uuid = row.get("id"); - id - } - None => { - tracing::info!("Transaction with reference {} already claimed or processed. Skipping success logic.", reference); - return Ok(()); - } - }; - - let mut transaction = state.pool.begin().await?; - - if let Err(e) = handle_purchase_success_db( - &mut transaction, - listing_id, - buyer_id, - seller_id, - tx_id, - now, - ).await { - tracing::error!("Error writing webhook purchase success updates: {:?}", e); - transaction.rollback().await?; - return Err(e); - } - - transaction.commit().await?; - - Ok(()) -} - -async fn handle_purchase_pending( - pool: &PgPool, - reference: &str, - amount: f64, - external_ref: &str, -) -> Result<(), AppError> { - let (listing_id, buyer_id) = parse_purchase_ref(external_ref)?; - - let listing_row = sqlx::query("SELECT seller_id FROM listings WHERE id = $1") - .bind(listing_id) - .fetch_optional(pool) - .await?; - - let listing = match listing_row { - Some(row) => row, - None => return Err(AppError::BadRequest(format!("Listing {} not found", listing_id))), - }; - let seller_id: Uuid = listing.get("seller_id"); - - let payout_amount = (amount * 0.95).floor(); - let commission_amount = amount - payout_amount; - - let now = Utc::now(); - sqlx::query( - "INSERT INTO transactions ( \ - payment_reference, listing_id, buyer_id, seller_id, amount, status, \ - payout_status, payout_reference, commission_amount, created_at \ - ) \ - VALUES ($1, $2, $3, $4, $5, 'pending_payment', 'pending', NULL, $6, $7) \ - ON CONFLICT (payment_reference) \ - DO UPDATE SET status = 'pending_payment' \ - WHERE transactions.status = 'pending_payment'" - ) - .bind(reference) - .bind(listing_id) - .bind(buyer_id) - .bind(seller_id) - .bind(amount) - .bind(commission_amount) - .bind(now) - .execute(pool) - .await?; - - Ok(()) -} - -pub async fn fapshi_webhook_handler( - State(state): State, - headers: HeaderMap, - Json(body): Json, -) -> Result { - verify_webhook_auth(&state.pool, &headers).await?; - - let payload_val = if let Some(arr) = body.as_array() { - if arr.is_empty() { - return Err(AppError::BadRequest("Empty payload array".to_string())); - } - &arr[0] - } else if body.is_object() { - &body - } else { - return Err(AppError::BadRequest("Invalid webhook payload format".to_string())); - }; - - let payload: FapshiWebhookPayload = serde_json::from_value(payload_val.clone()) - .map_err(|e| AppError::BadRequest(format!("Failed to parse webhook payload: {}", e)))?; - - let status = payload.status.or(payload.state).ok_or_else(|| AppError::BadRequest("Missing status/state field".to_string()))?; - let reference = payload.trans_id.or(payload.transaction_id).or(payload.id).ok_or_else(|| AppError::BadRequest("Missing transId/id reference field".to_string()))?; - let amount_val = payload.amount.ok_or_else(|| AppError::BadRequest("Missing amount field".to_string()))?; - let external_reference = payload.external_id.or(payload.external_reference).or(payload.custom).unwrap_or_default(); - - let amount = match amount_val { - serde_json::Value::Number(num) => num.as_f64().unwrap_or(0.0), - serde_json::Value::String(s) => s.parse::().unwrap_or(0.0), - _ => return Err(AppError::BadRequest("Invalid amount type".to_string())), - }; - - let status_upper = status.to_uppercase(); - - tracing::info!("Processing incoming Fapshi webhook for ref: {}, status: {}, external: {}", reference, status_upper, external_reference); - - if status_upper == "SUCCESSFUL" || status_upper == "SUCCESS" { - if external_reference.starts_with("boost:") || external_reference.starts_with("boost_") { - handle_boost_success(&state.pool, &reference, amount, &external_reference).await?; - } else if external_reference.starts_with("donation:") || external_reference.starts_with("donation_") { - handle_donation_success(&state.pool, &reference, amount, &external_reference).await?; - } else if external_reference.starts_with("purchase:") || external_reference.starts_with("purchase_") { - handle_purchase_success(&state, &reference, amount, &external_reference).await?; - } else { - tracing::warn!("Unknown externalReference: {}", external_reference); - } - } else if (status_upper == "CREATED" || status_upper == "PENDING" || status_upper == "PENDING_PAYMENT") - && (external_reference.starts_with("purchase:") || external_reference.starts_with("purchase_")) - { - handle_purchase_pending(&state.pool, &reference, amount, &external_reference).await?; - } else if (status_upper == "FAILED" || status_upper == "EXPIRED") - && (external_reference.starts_with("purchase:") || external_reference.starts_with("purchase_")) - { - tracing::info!("Marking transaction failed: Ref={}", reference); - sqlx::query("UPDATE transactions SET status = 'failed' WHERE payment_reference = $1") - .bind(&reference) - .execute(&state.pool) - .await?; - } - - Ok((axum::http::StatusCode::OK, Json(serde_json::json!({ "success": true })))) -} diff --git a/bookbridge-rust-core/tests/auth_tests.rs b/bookbridge-rust-core/tests/auth_tests.rs deleted file mode 100644 index 710c1bc..0000000 --- a/bookbridge-rust-core/tests/auth_tests.rs +++ /dev/null @@ -1,56 +0,0 @@ -use axum::{ - body::Body, - http::{Request, StatusCode}, - middleware, - routing::get, - Router, -}; -use std::sync::Arc; -use tower::ServiceExt; -use bookbridge_rust_core::{ - auth::require_internal_auth, - config::AppConfig, -}; - -#[tokio::test] -async fn test_auth_middleware() { - let config = Arc::new(AppConfig { - database_url: "postgres://dummy".to_string(), - internal_api_secret: "super_secret_key_12345".to_string(), - fapshi_base_url: "https://sandbox.fapshi.com".to_string(), - port: 8080, - }); - - let app = Router::new() - .route("/test", get(|| async { "ok" })) - .layer(middleware::from_fn_with_state( - config.clone(), - require_internal_auth, - )); - - // Case 1: Missing Header - let req = Request::builder() - .uri("/test") - .body(Body::empty()) - .unwrap(); - let response = app.clone().oneshot(req).await.unwrap(); - assert_eq!(response.status(), StatusCode::UNAUTHORIZED); - - // Case 2: Incorrect Header Value - let req = Request::builder() - .uri("/test") - .header("X-Internal-Secret", "wrong_secret") - .body(Body::empty()) - .unwrap(); - let response = app.clone().oneshot(req).await.unwrap(); - assert_eq!(response.status(), StatusCode::UNAUTHORIZED); - - // Case 3: Correct Header Value - let req = Request::builder() - .uri("/test") - .header("X-Internal-Secret", "super_secret_key_12345") - .body(Body::empty()) - .unwrap(); - let response = app.clone().oneshot(req).await.unwrap(); - assert_eq!(response.status(), StatusCode::OK); -} diff --git a/bookbridge-rust-core/tests/escrow_tests.rs b/bookbridge-rust-core/tests/escrow_tests.rs deleted file mode 100644 index ba91613..0000000 --- a/bookbridge-rust-core/tests/escrow_tests.rs +++ /dev/null @@ -1,294 +0,0 @@ -use bookbridge_rust_core::fapshi::FapshiClient; -use bookbridge_rust_core::routes::escrow::release_escrow; -use bookbridge_rust_core::AppState; -use sqlx::PgPool; -use uuid::Uuid; -use std::sync::Arc; -use std::sync::Mutex; -use std::collections::HashSet; - -#[test] -fn test_clean_phone() { - assert_eq!(FapshiClient::clean_phone("+237 677 889 900"), "677889900"); - assert_eq!(FapshiClient::clean_phone("655 444 333"), "655444333"); - assert_eq!(FapshiClient::clean_phone("237699111222"), "699111222"); - assert_eq!(FapshiClient::clean_phone("12345"), "12345"); - assert_eq!(FapshiClient::clean_phone(""), ""); -} - -#[tokio::test] -async fn test_release_escrow_db_integration() -> Result<(), Box> { - let _ = dotenvy::dotenv(); - - // Safety check: only run on explicit local development/test databases. - // Invert the skip check to guarantee we NEVER run against production databases like Supabase. - let db_url = match std::env::var("DATABASE_URL") { - Ok(url) if (url.contains("localhost") || url.contains("127.0.0.1") || url.contains("test") || url.contains("dev")) - && !url.contains("pooler.supabase.com") - && !url.contains("db.jacnsvcwmhoicuuzmrmr") => url, - _ => { - println!("Skipping DB integration test (requires a local/test DATABASE_URL, skipping production settings)"); - return Ok(()); - } - }; - - let pool = match PgPool::connect(&db_url).await { - Ok(p) => p, - Err(e) => { - println!("Skipping DB integration test (database connection failed: {})", e); - return Ok(()); - } - }; - - // Run setup within a transaction - let mut tx = pool.begin().await?; - - let seller_id = Uuid::new_v4(); - let buyer_id = Uuid::new_v4(); - let listing_id = Uuid::new_v4(); - let transaction_id = Uuid::new_v4(); - - // Insert mock auth users to satisfy foreign key constraints if possible. - let user_setup = sqlx::query( - "INSERT INTO auth.users (id, email) VALUES ($1, $2), ($3, $4)" - ) - .bind(seller_id) - .bind("seller@example.com") - .bind(buyer_id) - .bind("buyer@example.com") - .execute(&mut *tx) - .await; - - if let Err(e) = user_setup { - println!("Skipping query execution check (cannot insert dummy auth.users: {}).", e); - tx.rollback().await?; - return Ok(()); - } - - // Insert profile details - sqlx::query( - "INSERT INTO profiles (id, full_name, whatsapp_number) VALUES ($1, $2, $3)" - ) - .bind(seller_id) - .bind("Integration Test Seller") - .bind("+237677777777") - .execute(&mut *tx) - .await?; - - // Insert listing details - sqlx::query( - "INSERT INTO listings (id, seller_id, title, status) VALUES ($1, $2, $3, $4)" - ) - .bind(listing_id) - .bind(seller_id) - .bind("Integration Test Book") - .bind("active") - .execute(&mut *tx) - .await?; - - // Insert transactions details (status must be 'held' to match status check constraint & release rule) - sqlx::query( - "INSERT INTO transactions (id, listing_id, buyer_id, seller_id, amount, commission_amount, payment_reference, status) \ - VALUES ($1, $2, $3, $4, 5000, 250, 'integration_test_ref_99', 'held')" - ) - .bind(transaction_id) - .bind(listing_id) - .bind(buyer_id) - .bind(seller_id) - .execute(&mut *tx) - .await?; - - // Insert escrow transactions details - sqlx::query( - "INSERT INTO escrow_transactions (transaction_id, status) VALUES ($1, 'held')" - ) - .bind(transaction_id) - .execute(&mut *tx) - .await?; - - // Ensure our Fapshi credentials table contains mock values to satisfy lookups - sqlx::query( - "INSERT INTO app_secrets (key, value) VALUES ($1, $2), ($3, $4) \ - ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value" - ) - .bind("fapshi_payout_api_user") - .bind("mock_payout_user") - .bind("fapshi_payout_api_key") - .bind("mock_payout_key") - .execute(&mut *tx) - .await?; - - // Commit the setup transaction so the database pool connections can read it - tx.commit().await?; - - let state = AppState { - pool: pool.clone(), - in_progress_payouts: Arc::new(Mutex::new(HashSet::new())), - fapshi_base_url: "https://sandbox.fapshi.com".to_string(), // Mock sandbox URL for testing - }; - - // Executing the escrow release. - let result = release_escrow(&state, transaction_id).await; - - // Manual cleanup to leave the database clean - let _ = sqlx::query("DELETE FROM app_secrets WHERE key IN ('fapshi_payout_api_user', 'fapshi_payout_api_key')").execute(&pool).await; - let _ = sqlx::query("DELETE FROM escrow_transactions WHERE transaction_id = $1").bind(transaction_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM transactions WHERE id = $1").bind(transaction_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM listings WHERE id = $1").bind(listing_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM profiles WHERE id = $1").bind(seller_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM auth.users WHERE id IN ($1, $2)").bind(seller_id).bind(buyer_id).execute(&pool).await; - - // Verify database status checks compiled and succeeded by ensuring the execution failed - // ONLY at the network boundary (Reqwest error attempting to reach sandbox.fapshi.com) - match result { - Ok(_) => { - panic!("Expected Fapshi payout network call to fail, but it returned Ok"); - } - Err(bookbridge_rust_core::error::AppError::Reqwest(e)) => { - let err_str = e.to_string(); - println!("Success: Database queries verified successfully up to the network boundary: {}", err_str); - assert!( - err_str.contains("dns") - || err_str.contains("connect") - || err_str.contains("builder") - || err_str.contains("resolve") - ); - } - Err(other) => { - panic!("Escrow release failed at database query/state checking stage before network: {:?}", other); - } - } - - Ok(()) -} - -#[tokio::test] -async fn test_poll_pending_db_integration() -> Result<(), Box> { - let _ = dotenvy::dotenv(); - - // Safety check: skip running against production database strings - let db_url = match std::env::var("DATABASE_URL") { - Ok(url) if (url.contains("localhost") || url.contains("127.0.0.1") || url.contains("test") || url.contains("dev")) - && !url.contains("pooler.supabase.com") - && !url.contains("db.jacnsvcwmhoicuuzmrmr") => url, - _ => { - println!("Skipping DB poll pending integration test (requires a local/test DATABASE_URL)"); - return Ok(()); - } - }; - - let pool = match PgPool::connect(&db_url).await { - Ok(p) => p, - Err(e) => { - println!("Skipping DB poll pending integration test (database connection failed: {})", e); - return Ok(()); - } - }; - - let mut tx = pool.begin().await?; - - let seller_id = Uuid::new_v4(); - let buyer_id = Uuid::new_v4(); - let listing_id = Uuid::new_v4(); - let transaction_id = Uuid::new_v4(); - - // Insert mock auth users - let user_setup = sqlx::query( - "INSERT INTO auth.users (id, email) VALUES ($1, $2), ($3, $4)" - ) - .bind(seller_id) - .bind("seller-poll@example.com") - .bind(buyer_id) - .bind("buyer-poll@example.com") - .execute(&mut *tx) - .await; - - if let Err(e) = user_setup { - println!("Skipping poll pending query check (cannot insert dummy auth.users: {}).", e); - tx.rollback().await?; - return Ok(()); - } - - // Insert profile - sqlx::query( - "INSERT INTO profiles (id, full_name, whatsapp_number) VALUES ($1, $2, $3)" - ) - .bind(seller_id) - .bind("Poll Test Seller") - .bind("+237677777778") - .execute(&mut *tx) - .await?; - - // Insert listing - sqlx::query( - "INSERT INTO listings (id, seller_id, title, status) VALUES ($1, $2, $3, $4)" - ) - .bind(listing_id) - .bind(seller_id) - .bind("Poll Test Book") - .bind("active") - .execute(&mut *tx) - .await?; - - // Insert transaction stuck in pending_payment (using an old date to trigger the 10-minute rule) - let ten_minutes_ago = chrono::Utc::now() - chrono::Duration::minutes(15); - sqlx::query( - "INSERT INTO transactions (id, listing_id, buyer_id, seller_id, amount, commission_amount, payment_reference, status, created_at) \ - VALUES ($1, $2, $3, $4, 5000, 250, 'poll_test_ref_999', 'pending_payment', $5)" - ) - .bind(transaction_id) - .bind(listing_id) - .bind(buyer_id) - .bind(seller_id) - .bind(ten_minutes_ago) - .execute(&mut *tx) - .await?; - - // Mock app secrets for polling - sqlx::query( - "INSERT INTO app_secrets (key, value) VALUES ($1, $2), ($3, $4) \ - ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value" - ) - .bind("fapshi_api_user") - .bind("mock_api_user") - .bind("fapshi_api_key") - .bind("mock_api_key") - .execute(&mut *tx) - .await?; - - // Commit setup transaction so poll_payment_status can read from pool connections - tx.commit().await?; - - let fapshi = FapshiClient::new("https://sandbox.fapshi.com".to_string()); - - // Call status checking. Since we use a mock api key and are offline, this will hit connection/Fapshi error. - let result = fapshi.poll_payment_status(&pool, transaction_id, "poll_test_ref_999").await; - - // Manual cleanup - let _ = sqlx::query("DELETE FROM app_secrets WHERE key IN ('fapshi_api_user', 'fapshi_api_key')").execute(&pool).await; - let _ = sqlx::query("DELETE FROM transactions WHERE id = $1").bind(transaction_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM listings WHERE id = $1").bind(listing_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM profiles WHERE id = $1").bind(seller_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM auth.users WHERE id IN ($1, $2)").bind(seller_id).bind(buyer_id).execute(&pool).await; - - match result { - Ok(status) => { - println!("Status query completed with state: {}", status); - } - Err(bookbridge_rust_core::error::AppError::Reqwest(e)) => { - let err_str = e.to_string(); - println!("Success: Polling DB setup verified up to the network boundary: {}", err_str); - assert!( - err_str.contains("dns") - || err_str.contains("connect") - || err_str.contains("builder") - || err_str.contains("resolve") - ); - } - Err(other) => { - panic!("Polling status check failed during database querying/state validation: {:?}", other); - } - } - - Ok(()) -} diff --git a/bookbridge-rust-core/tests/webhook_tests.rs b/bookbridge-rust-core/tests/webhook_tests.rs deleted file mode 100644 index 5ffcb32..0000000 --- a/bookbridge-rust-core/tests/webhook_tests.rs +++ /dev/null @@ -1,235 +0,0 @@ -use bookbridge_rust_core::routes::webhook::fapshi_webhook_handler; -use bookbridge_rust_core::AppState; -use axum::{routing::post, Router, body::Body, http::{Request, StatusCode}}; -use sqlx::PgPool; -use uuid::Uuid; -use std::sync::Arc; -use std::sync::Mutex; -use std::collections::HashSet; -use tower::ServiceExt; - -#[tokio::test] -async fn test_webhook_integration() -> Result<(), Box> { - let _ = dotenvy::dotenv(); - - // Safety check: only run on local test databases - let db_url = match std::env::var("DATABASE_URL") { - Ok(url) if (url.contains("localhost") || url.contains("127.0.0.1") || url.contains("test") || url.contains("dev")) - && !url.contains("pooler.supabase.com") - && !url.contains("db.jacnsvcwmhoicuuzmrmr") => url, - _ => { - println!("Skipping webhook DB integration tests (non-local DATABASE_URL)"); - return Ok(()); - } - }; - - let pool = match PgPool::connect(&db_url).await { - Ok(p) => p, - Err(e) => { - println!("Skipping webhook DB integration tests (connection failed: {})", e); - return Ok(()); - } - }; - - // Setup mock rows in a transaction, then commit - let mut tx = pool.begin().await?; - - let seller_id = Uuid::new_v4(); - let buyer_id = Uuid::new_v4(); - let listing_id = Uuid::new_v4(); - let transaction_id = Uuid::new_v4(); - let payment_ref = format!("web_test_ref_{}", Uuid::new_v4().to_string().replace("-", "")); - - // Mock auth users - let user_setup = sqlx::query( - "INSERT INTO auth.users (id, email) VALUES ($1, $2), ($3, $4)" - ) - .bind(seller_id) - .bind("wh-seller@example.com") - .bind(buyer_id) - .bind("wh-buyer@example.com") - .execute(&mut *tx) - .await; - - if let Err(e) = user_setup { - println!("Skipping webhook DB check (cannot insert dummy auth.users: {}).", e); - tx.rollback().await?; - return Ok(()); - } - - // Profiles - sqlx::query("INSERT INTO profiles (id, full_name, whatsapp_number) VALUES ($1, $2, $3)") - .bind(seller_id).bind("Webhook Seller").bind("+237612345678") - .execute(&mut *tx).await?; - - // Listing - sqlx::query("INSERT INTO listings (id, seller_id, title, status) VALUES ($1, $2, $3, $4)") - .bind(listing_id).bind(seller_id).bind("Webhook Book").bind("active") - .execute(&mut *tx).await?; - - // Initial Transaction in pending_payment state - sqlx::query( - "INSERT INTO transactions (id, listing_id, buyer_id, seller_id, amount, status, payout_status, payment_reference) \ - VALUES ($1, $2, $3, $4, 5000, 'pending_payment', 'pending', $5)" - ) - .bind(transaction_id) - .bind(listing_id) - .bind(buyer_id) - .bind(seller_id) - .bind(&payment_ref) - .execute(&mut *tx) - .await?; - - // App secrets for webhook authentication - sqlx::query( - "INSERT INTO app_secrets (key, value) VALUES ($1, $2), ($3, $4), ($5, $6) \ - ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value" - ) - .bind("fapshi_webhook_secret").bind("wh_test_key_xyz") - .bind("fapshi_api_user").bind("wh_test_payout_user") - .bind("fapshi_api_key").bind("wh_test_payout_key") - .execute(&mut *tx) - .await?; - - tx.commit().await?; - - // Initialize State - let state = AppState { - pool: pool.clone(), - in_progress_payouts: Arc::new(Mutex::new(HashSet::new())), - fapshi_base_url: "https://sandbox.fapshi.com".to_string(), - }; - - let app = Router::new() - .route("/webhooks/fapshi", post(fapshi_webhook_handler)) - .with_state(state); - - // --- TEST CASE 1: Unauthorized Webhook (Invalid Key) --- - { - let payload = serde_json::json!({ - "status": "SUCCESSFUL", - "transId": "fapshi_tx_111", - "amount": 5000, - "externalId": format!("purchase:{}:{}", listing_id, buyer_id) - }); - - let req = Request::builder() - .method("POST") - .uri("/webhooks/fapshi") - .header("Content-Type", "application/json") - .header("x-wh-secret", "invalid_secret") - .body(Body::from(serde_json::to_string(&payload)?)) - .unwrap(); - - let response = app.clone().oneshot(req).await.unwrap(); - assert_eq!(response.status(), StatusCode::UNAUTHORIZED); - } - - // --- TEST CASE 2: Malformed Payload (400 Bad Request) --- - { - let req = Request::builder() - .method("POST") - .uri("/webhooks/fapshi") - .header("Content-Type", "application/json") - .header("x-wh-secret", "wh_test_key_xyz") - .body(Body::from("{ malformed json }")) - .unwrap(); - - let response = app.clone().oneshot(req).await.unwrap(); - assert_eq!(response.status(), StatusCode::BAD_REQUEST); - } - - // --- TEST CASE 3: Successful Purchase Webhook --- - { - // Target the standard reference we setup - let mock_payload = serde_json::json!([{ - "status": "SUCCESSFUL", - "transId": &payment_ref, // Use the payment_reference as Fapshi transId - "amount": "5000", - "externalId": format!("purchase:{}:{}", listing_id, buyer_id) - }]); - - let req = Request::builder() - .method("POST") - .uri("/webhooks/fapshi") - .header("Content-Type", "application/json") - .header("x-wh-secret", "wh_test_key_xyz") - .body(Body::from(serde_json::to_string(&mock_payload)?)) - .unwrap(); - - let response = app.clone().oneshot(req).await.unwrap(); - assert_eq!(response.status(), StatusCode::OK); - - // Verify database updates - let tx_state: (String, String) = sqlx::query_as("SELECT status, payout_status FROM transactions WHERE id = $1") - .bind(transaction_id) - .fetch_one(&pool) - .await?; - assert_eq!(tx_state.0, "held"); - assert_eq!(tx_state.1, "pending"); - - let listing_state: (String,) = sqlx::query_as("SELECT status FROM listings WHERE id = $1") - .bind(listing_id) - .fetch_one(&pool) - .await?; - assert_eq!(listing_state.0, "sold"); - - let escrow_count: (i64,) = sqlx::query_as("SELECT count(*) FROM escrow_transactions WHERE transaction_id = $1") - .bind(transaction_id) - .fetch_one(&pool) - .await?; - assert_eq!(escrow_count.0, 1); - - let msg_count: (i64,) = sqlx::query_as("SELECT count(*) FROM messages WHERE listing_id = $1") - .bind(listing_id) - .fetch_one(&pool) - .await?; - assert_eq!(msg_count.0, 1); - } - - // --- TEST CASE 4: Duplicate Webhook Delivery (No-op check) --- - { - // Re-deliver same success payload - let mock_payload = serde_json::json!([{ - "status": "SUCCESSFUL", - "transId": &payment_ref, - "amount": "5000", - "externalId": format!("purchase:{}:{}", listing_id, buyer_id) - }]); - - let req = Request::builder() - .method("POST") - .uri("/webhooks/fapshi") - .header("Content-Type", "application/json") - .header("x-wh-secret", "wh_test_key_xyz") - .body(Body::from(serde_json::to_string(&mock_payload)?)) - .unwrap(); - - let response = app.clone().oneshot(req).await.unwrap(); - assert_eq!(response.status(), StatusCode::OK); - - // Verify no duplicates were created - let escrow_count: (i64,) = sqlx::query_as("SELECT count(*) FROM escrow_transactions WHERE transaction_id = $1") - .bind(transaction_id) - .fetch_one(&pool) - .await?; - assert_eq!(escrow_count.0, 1); // Remains exactly 1 (no duplicate row) - - let msg_count: (i64,) = sqlx::query_as("SELECT count(*) FROM messages WHERE listing_id = $1") - .bind(listing_id) - .fetch_one(&pool) - .await?; - assert_eq!(msg_count.0, 1); // Remains exactly 1 - } - - // Manual database cleanup - let _ = sqlx::query("DELETE FROM app_secrets WHERE key IN ('fapshi_webhook_secret', 'fapshi_api_user', 'fapshi_api_key')").execute(&pool).await; - let _ = sqlx::query("DELETE FROM messages WHERE listing_id = $1").bind(listing_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM escrow_transactions WHERE transaction_id = $1").bind(transaction_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM transactions WHERE id = $1").bind(transaction_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM listings WHERE id = $1").bind(listing_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM profiles WHERE id = $1").bind(seller_id).execute(&pool).await; - let _ = sqlx::query("DELETE FROM auth.users WHERE id IN ($1, $2)").bind(seller_id).bind(buyer_id).execute(&pool).await; - - Ok(()) -} diff --git a/git_final_out.txt b/git_final_out.txt deleted file mode 100644 index 8b76e05..0000000 --- a/git_final_out.txt +++ /dev/null @@ -1,9 +0,0 @@ -[dev 908a831] feat: implement boost listing priority, visual badge, and fix keyboard overlap in payment sheet - 1 file changed, 0 insertions(+), 0 deletions(-) - create mode 100644 git_final_out.txt -To https://github.com/DCT-Berinyuy/book-bridge.git - f5834ea..908a831 dev -> dev -error: Your local changes to the following files would be overwritten by checkout: - git_final_out.txt -Please commit your changes or stash them before you switch branches. -Aborting diff --git a/git_log_final.txt b/git_log_final.txt deleted file mode 100644 index d53bae2..0000000 --- a/git_log_final.txt +++ /dev/null @@ -1,39 +0,0 @@ -commit c53a46e3a4072d7b10d7429524a87b41d8f7bd3d -Author: DCT-Berinyuy -Date: Sat Feb 28 03:40:25 2026 +0100 - - feat: add Sold and Boosted badges to ListingDetailsScreen - - - Fix missing 'boosted' translation key in ARB files - - Implement _buildSoldBadge and _buildBoostedBadge in ListingDetailsScreen - - Add badges to the header of the details view - -commit b7ccb736ac5e3df203a2861c040f36b687f7d4f3 -Author: DCT-Berinyuy -Date: Sat Feb 28 02:51:21 2026 +0100 - - feat: complete Phase 4 In-App Payments - - - Create and migrate transactions table - - Implement Purchase logic in Svelte webhook to update 'Sold' listing status - - Handle initial automated Buyer<>Seller message creation on successful purchase - - Show localized 'Sold' UI badge and disable buying/chatting - - Added English/French localizations for Sold state - -commit 908a831d591efd7ae60d58739e4e191c708a6f9f -Author: DCT-Berinyuy -Date: Fri Feb 27 18:47:15 2026 +0100 - - feat: implement boost listing priority, visual badge, and fix keyboard overlap in payment sheet - -commit 4e5c7ff0b1aaa3684e5437695cffffce14883f49 -Author: DCT-Berinyuy -Date: Fri Feb 27 18:15:57 2026 +0100 - - feat: implement boost listing priority, visual badge, and fix keyboard overlap in payment sheet - -commit f5834eaaafb6955532b9ad280c925b560cfa4a51 -Author: DCT-Berinyuy -Date: Fri Feb 27 17:29:40 2026 +0100 - - feat: implement in-app chat, unread badge, and buy/pay now buttons diff --git a/git_log_now.txt b/git_log_now.txt deleted file mode 100644 index 7ab8e03..0000000 --- a/git_log_now.txt +++ /dev/null @@ -1,11 +0,0 @@ -commit b7ccb736ac5e3df203a2861c040f36b687f7d4f3 -Author: DCT-Berinyuy -Date: Sat Feb 28 02:51:21 2026 +0100 - - feat: complete Phase 4 In-App Payments - - - Create and migrate transactions table - - Implement Purchase logic in Svelte webhook to update 'Sold' listing status - - Handle initial automated Buyer<>Seller message creation on successful purchase - - Show localized 'Sold' UI badge and disable buying/chatting - - Added English/French localizations for Sold state diff --git a/git_merge_push_log.txt b/git_merge_push_log.txt deleted file mode 100644 index 93013ad..0000000 --- a/git_merge_push_log.txt +++ /dev/null @@ -1,2 +0,0 @@ -To https://github.com/DCT-Berinyuy/book-bridge.git - f335180..f5834ea dev -> dev diff --git a/git_status_debug.txt b/git_status_debug.txt deleted file mode 100644 index d748e31..0000000 --- a/git_status_debug.txt +++ /dev/null @@ -1,25 +0,0 @@ -On branch dev -Your branch is up to date with 'origin/dev'. - -Changes not staged for commit: - (use "git add ..." to update what will be committed) - (use "git restore ..." to discard changes in working directory) - modified: lib/config/router.dart - modified: lib/core/presentation/widgets/scaffold_with_navbar.dart - modified: lib/features/listings/presentation/screens/listing_details_screen.dart - modified: lib/injection_container.dart - modified: lib/l10n/app_en.arb - modified: lib/l10n/app_fr.arb - modified: lib/l10n/app_localizations.dart - modified: lib/l10n/app_localizations_en.dart - modified: lib/l10n/app_localizations_fr.dart - modified: lib/main.dart - modified: pubspec.yaml - -Untracked files: - (use "git add ..." to include in what will be committed) - git_status_debug.txt - lib/features/chat/ - test/ - -no changes added to commit (use "git add" and/or "git commit -a") diff --git a/git_status_now.txt b/git_status_now.txt deleted file mode 100644 index 9e49354..0000000 --- a/git_status_now.txt +++ /dev/null @@ -1,9 +0,0 @@ -On branch dev -Your branch is ahead of 'origin/dev' by 1 commit. - (use "git push" to publish your local commits) - -Untracked files: - (use "git add ..." to include in what will be committed) - git_status_now.txt - -nothing added to commit but untracked files present (use "git add" to track) diff --git a/supabase/favorites_migration.sql b/supabase/favorites_migration.sql deleted file mode 100644 index 90bcad0..0000000 --- a/supabase/favorites_migration.sql +++ /dev/null @@ -1,53 +0,0 @@ --- SQL Migration: Favorites Functionality - --- 1. Create favorites table -CREATE TABLE IF NOT EXISTS public.favorites ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, - listing_id UUID NOT NULL REFERENCES public.listings(id) ON DELETE CASCADE, - created_at TIMESTAMPTZ DEFAULT now(), - -- Prevent duplicate favorites - UNIQUE(user_id, listing_id) -); - --- 2. Enable RLS -ALTER TABLE public.favorites ENABLE ROW LEVEL SECURITY; - --- 3. RLS Policies -CREATE POLICY "Users can view their own favorites" -ON public.favorites FOR SELECT -USING (auth.uid() = user_id); - -CREATE POLICY "Users can create their own favorites" -ON public.favorites FOR INSERT -WITH CHECK (auth.uid() = user_id); - -CREATE POLICY "Users can delete their own favorites" -ON public.favorites FOR DELETE -USING (auth.uid() = user_id); - --- 4. Create wishlists table -CREATE TABLE IF NOT EXISTS public.wishlists ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, - listing_id UUID NOT NULL REFERENCES public.listings(id) ON DELETE CASCADE, - created_at TIMESTAMPTZ DEFAULT now(), - -- Prevent duplicate wishlists - UNIQUE(user_id, listing_id) -); - --- 5. Enable RLS for wishlists -ALTER TABLE public.wishlists ENABLE ROW LEVEL SECURITY; - --- 6. RLS Policies for wishlists -CREATE POLICY "Users can view their own wishlists" -ON public.wishlists FOR SELECT -USING (auth.uid() = user_id); - -CREATE POLICY "Users can create their own wishlists" -ON public.wishlists FOR INSERT -WITH CHECK (auth.uid() = user_id); - -CREATE POLICY "Users can delete their own wishlists" -ON public.wishlists FOR DELETE -USING (auth.uid() = user_id); diff --git a/supabase/feedback_migration.sql b/supabase/feedback_migration.sql deleted file mode 100644 index e641e84..0000000 --- a/supabase/feedback_migration.sql +++ /dev/null @@ -1,20 +0,0 @@ --- Create feedback table -CREATE TABLE IF NOT EXISTS public.feedback ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL, - content TEXT NOT NULL, - created_at TIMESTAMPTZ DEFAULT now() -); - --- Enable RLS -ALTER TABLE public.feedback ENABLE ROW LEVEL SECURITY; - --- Create policy to allow users to insert their own feedback -CREATE POLICY "Users can insert their own feedback" -ON public.feedback -FOR INSERT -TO authenticated -WITH CHECK (auth.uid() = user_id); - --- Create policy to allow team to read all feedback (Optional: you can adjust this later) --- For now, let's keep it private or for service_role only. diff --git a/supabase/functions/fapshi-polling/index.ts b/supabase/functions/fapshi-polling/index.ts deleted file mode 100644 index 927745c..0000000 --- a/supabase/functions/fapshi-polling/index.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; - -const supabaseUrl = Deno.env.get("SUPABASE_URL")!; -const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; - -function adminClient() { - return createClient(supabaseUrl, supabaseServiceKey); -} - -function resp(status: number, body: unknown): Response { - return new Response(JSON.stringify(body), { - status, - headers: { "Content-Type": "application/json" }, - }); -} - -Deno.serve(async (req: Request) => { - try { - // Validate cron secret - const supabase = adminClient(); - const cronSecret = req.headers.get("x-cron-secret"); - const { data: secretRow } = await supabase - .from("app_secrets") - .select("value") - .eq("key", "broadcast_secret") - .single(); - - if (!cronSecret || cronSecret !== secretRow?.value) { - return resp(401, { error: "Unauthorized" }); - } - - // Retrieve Fapshi credentials from database secrets - const { data: userRow } = await supabase - .from("app_secrets") - .select("value") - .eq("key", "fapshi_api_user") - .single(); - const { data: keyRow } = await supabase - .from("app_secrets") - .select("value") - .eq("key", "fapshi_api_key") - .single(); - - const fapshiApiUser = userRow?.value; - const fapshiApiKey = keyRow?.value; - - if (!fapshiApiUser || !fapshiApiKey) { - return resp(500, { error: "Fapshi API credentials not configured in app_secrets" }); - } - - // Find all transactions stuck in pending_payment for more than 10 minutes - const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000).toISOString(); - const { data: txs, error: txsErr } = await supabase - .from("transactions") - .select("id, payment_reference, listing_id, buyer_id, seller_id, amount") - .eq("status", "pending_payment") - .lte("created_at", tenMinutesAgo); - - if (txsErr) { - return resp(500, { error: txsErr.message }); - } - - const results: Array<{ id: string; reference: string; status: string; error?: string }> = []; - - for (const tx of txs ?? []) { - const reference = tx.payment_reference; - try { - console.log(`Checking Fapshi status for transaction ref: ${reference}`); - const fapshiRes = await fetch(`https://api.fapshi.com/payment-status/${reference}`, { - method: "GET", - headers: { - "apiuser": fapshiApiUser, - "apikey": fapshiApiKey, - }, - }); - - if (!fapshiRes.ok) { - const errMsg = await fapshiRes.text(); - results.push({ id: tx.id, reference, status: "error", error: `Fapshi error: ${fapshiRes.status} - ${errMsg}` }); - console.error(`Fapshi status check failed for ${reference}: ${fapshiRes.status} - ${errMsg}`); - continue; - } - - const data = await fapshiRes.json(); - const fapshiStatus = data.status || data.state; - console.log(`Fapshi status for ${reference} is ${fapshiStatus}`); - - if (fapshiStatus === "SUCCESSFUL" || fapshiStatus === "SUCCESS") { - // Process successful payment - // 1. Mark listing as sold - await supabase - .from("listings") - .update({ status: "sold" }) - .eq("id", tx.listing_id); - - // 2. Update transaction status to held (since escrow is enabled) - await supabase - .from("transactions") - .update({ status: "held" }) - .eq("id", tx.id); - - // 3. Create escrow transaction - await supabase - .from("escrow_transactions") - .upsert({ - transaction_id: tx.id, - status: "held", - created_at: new Date().toISOString(), - updated_at: new Date().toISOString(), - }, { onConflict: "transaction_id" }); - - // 4. Send automated chat message - await supabase - .from("messages") - .insert({ - listing_id: tx.listing_id, - sender_id: tx.buyer_id, - receiver_id: tx.seller_id, - content: "Hello! I just purchased this book via BookBridge. When can we meet to complete the exchange?", - is_read: false, - created_at: new Date().toISOString(), - }); - - results.push({ id: tx.id, reference, status: "held" }); - } else if (fapshiStatus === "FAILED" || fapshiStatus === "EXPIRED") { - // Mark transaction as failed - await supabase - .from("transactions") - .update({ status: "failed" }) - .eq("id", tx.id); - - results.push({ id: tx.id, reference, status: "failed" }); - } else { - // Still pending/created - results.push({ id: tx.id, reference, status: fapshiStatus }); - } - } catch (err) { - results.push({ id: tx.id, reference, status: "error", error: String(err) }); - console.error(`Error processing status check for ${reference}:`, err); - } - } - - return resp(200, { processed: results.length, results }); - } catch (err) { - console.error("fapshi-polling unhandled error:", err); - return resp(500, { error: String(err) }); - } -}); diff --git a/supabase/functions/process-escrow/index.ts b/supabase/functions/process-escrow/index.ts deleted file mode 100644 index 5cbc51d..0000000 --- a/supabase/functions/process-escrow/index.ts +++ /dev/null @@ -1,382 +0,0 @@ -import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; - -const supabaseUrl = Deno.env.get("SUPABASE_URL")!; -const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; -const FAPSHI_PAYOUT_URL = "https://live.fapshi.com/payout"; - -// --------------------------------------------------------------------------- -// Helpers -// --------------------------------------------------------------------------- - -function adminClient() { - return createClient(supabaseUrl, supabaseServiceKey); -} - -function userClient(jwt: string) { - return createClient(supabaseUrl, Deno.env.get("SUPABASE_ANON_KEY")!, { - global: { headers: { Authorization: `Bearer ${jwt}` } }, - }); -} - -/** Returns the bearer token from the Authorization header, or null. */ -function extractJwt(req: Request): string | null { - const auth = req.headers.get("Authorization"); - if (!auth?.startsWith("Bearer ")) return null; - return auth.slice(7); -} - -/** Verify the caller is an admin via service_role key or a trusted cron secret. */ -function isAdmin(req: Request): boolean { - const cronSecret = req.headers.get("x-cron-secret"); - if (cronSecret) { - // validated below in auto-release; here we just flag that it came via cron header - return true; - } - const authKey = req.headers.get("x-supabase-admin-key"); - return authKey === supabaseServiceKey; -} - -/** - * Execute a payout via Fapshi and return { ok, transId, error }. - * Statuses are NEVER updated unless this returns ok = true. - */ -async function executeFapshiPayout(params: { - amount: number; - phone: string; - sellerName: string; - externalId: string; - listingId: string; - transactionId: string; -}): Promise<{ ok: boolean; transId?: string; error?: string }> { - let cleanedPhone = params.phone.replace(/\D/g, ""); - if (cleanedPhone.startsWith("237")) cleanedPhone = cleanedPhone.slice(3); - - const requestPayload = { - amount: params.amount, - phone: cleanedPhone, - name: params.sellerName, - externalId: params.externalId, - message: `BookBridge escrow payout for listing ${params.listingId}`, - }; - - let res: Response; - let responsePayload: any = null; - let statusCode = 0; - - const supabase = adminClient(); - - // Retrieve Fapshi payout credentials from database secrets - const { data: userRow } = await supabase - .from("app_secrets") - .select("value") - .eq("key", "fapshi_payout_api_user") - .single(); - const { data: keyRow } = await supabase - .from("app_secrets") - .select("value") - .eq("key", "fapshi_payout_api_key") - .single(); - - const fapshiPayoutUser = userRow?.value; - const fapshiPayoutKey = keyRow?.value; - - if (!fapshiPayoutUser || !fapshiPayoutKey) { - return { ok: false, error: "Fapshi payout credentials not configured in app_secrets" }; - } - - try { - res = await fetch(FAPSHI_PAYOUT_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - apiuser: fapshiPayoutUser, - apikey: fapshiPayoutKey, - }, - body: JSON.stringify(requestPayload), - }); - statusCode = res.status; - responsePayload = await res.json().catch(() => ({})); - } catch (err) { - await supabase.from("fapshi_audit_logs").insert({ - transaction_id: params.transactionId, - endpoint: FAPSHI_PAYOUT_URL, - request_payload: requestPayload, - response_payload: { error: String(err) }, - status_code: 500, - }); - return { ok: false, error: `Network error: ${String(err)}` }; - } - - await supabase.from("fapshi_audit_logs").insert({ - transaction_id: params.transactionId, - endpoint: FAPSHI_PAYOUT_URL, - request_payload: requestPayload, - response_payload: responsePayload, - status_code: statusCode, - }); - - if (res.ok && responsePayload?.statusCode === 200) { - return { ok: true, transId: responsePayload.transId }; - } - return { - ok: false, - error: `Fapshi error ${res.status}: ${JSON.stringify(responsePayload)}`, - }; -} - -/** - * Release a single escrow: - * 1. Fetch transaction + seller profile. - * 2. Execute Fapshi payout. - * 3. ONLY on success → update escrow + transaction statuses. - * Returns { ok, error? }. - */ -async function releaseEscrow( - transactionId: string, - supabase = adminClient() -): Promise<{ ok: boolean; error?: string }> { - // Fetch transaction - const { data: tx, error: txErr } = await supabase - .from("transactions") - .select("id, listing_id, seller_id, amount, commission_amount, payment_reference") - .eq("id", transactionId) - .single(); - - if (txErr || !tx) { - return { ok: false, error: `Transaction not found: ${txErr?.message}` }; - } - - // Fetch seller profile - const { data: profile } = await supabase - .from("profiles") - .select("whatsapp_number, full_name") - .eq("id", tx.seller_id) - .single(); - - if (!profile?.whatsapp_number) { - return { ok: false, error: "Seller has no payout number configured." }; - } - - const payoutAmount = tx.amount - (tx.commission_amount ?? 0); - const externalId = `escrow_payout_${tx.payment_reference}`; - - // ── PAYOUT FIRST ──────────────────────────────────────────────────────── - const payout = await executeFapshiPayout({ - amount: payoutAmount, - phone: profile.whatsapp_number, - sellerName: profile.full_name ?? "BookBridge Seller", - externalId, - listingId: tx.listing_id, - transactionId: tx.id, - }); - - if (!payout.ok) { - return { ok: false, error: payout.error }; - } - // ── ONLY UPDATE DB AFTER CONFIRMED PAYOUT ──────────────────────────────── - - const now = new Date().toISOString(); - - const { error: escrowErr } = await supabase - .from("escrow_transactions") - .update({ status: "released", updated_at: now }) - .eq("transaction_id", transactionId) - .eq("status", "held"); - - if (escrowErr) { - console.error("escrow update failed after payout:", escrowErr); - // Payout already sent — log but don't surface as failure - } - - const { error: txUpdateErr } = await supabase - .from("transactions") - .update({ - status: "successful", - payout_status: "successful", - payout_reference: payout.transId, - }) - .eq("id", transactionId); - - if (txUpdateErr) { - console.error("transaction update failed after payout:", txUpdateErr); - } - - return { ok: true }; -} - -// --------------------------------------------------------------------------- -// Route handlers -// --------------------------------------------------------------------------- - -async function handleRelease(req: Request): Promise { - const jwt = extractJwt(req); - if (!jwt) return resp(401, { error: "Unauthorized" }); - - const { transaction_id } = await req.json(); - if (!transaction_id) return resp(400, { error: "transaction_id required" }); - - // Verify caller is the buyer - const client = userClient(jwt); - const { data: { user } } = await client.auth.getUser(); - if (!user) return resp(401, { error: "Invalid token" }); - - const { data: tx } = await adminClient() - .from("transactions") - .select("buyer_id, status") - .eq("id", transaction_id) - .single(); - - if (!tx) return resp(404, { error: "Transaction not found" }); - if (tx.buyer_id !== user.id) return resp(403, { error: "Forbidden" }); - if (tx.status !== "held") return resp(409, { error: `Transaction is '${tx.status}', not 'held'` }); - - const result = await releaseEscrow(transaction_id); - return result.ok - ? resp(200, { ok: true }) - : resp(500, { error: result.error }); -} - -async function handleDispute(req: Request): Promise { - const jwt = extractJwt(req); - if (!jwt) return resp(401, { error: "Unauthorized" }); - - const { transaction_id, dispute_reason } = await req.json(); - if (!transaction_id || !dispute_reason) { - return resp(400, { error: "transaction_id and dispute_reason required" }); - } - - const client = userClient(jwt); - const { data: { user } } = await client.auth.getUser(); - if (!user) return resp(401, { error: "Invalid token" }); - - const supabase = adminClient(); - - const { data: tx } = await supabase - .from("transactions") - .select("buyer_id, status") - .eq("id", transaction_id) - .single(); - - if (!tx) return resp(404, { error: "Transaction not found" }); - if (tx.buyer_id !== user.id) return resp(403, { error: "Forbidden" }); - if (tx.status !== "held") return resp(409, { error: `Transaction is '${tx.status}', not 'held'` }); - - const now = new Date().toISOString(); - - await supabase - .from("escrow_transactions") - .update({ status: "disputed", dispute_reason, updated_at: now }) - .eq("transaction_id", transaction_id); - - await supabase - .from("transactions") - .update({ status: "disputed" }) - .eq("id", transaction_id); - - return resp(200, { ok: true }); -} - -async function handleAutoReleaseExpired(req: Request): Promise { - // Validate cron secret - const supabase = adminClient(); - const cronSecret = req.headers.get("x-cron-secret"); - const { data: secretRow } = await supabase - .from("app_secrets") - .select("value") - .eq("key", "broadcast_secret") - .single(); - - if (!cronSecret || cronSecret !== secretRow?.value) { - return resp(401, { error: "Unauthorized" }); - } - - // Find all held escrows whose release_deadline has passed - const { data: expired, error } = await supabase - .from("escrow_transactions") - .select("transaction_id") - .eq("status", "held") - .lte("release_deadline", new Date().toISOString()); - - if (error) return resp(500, { error: error.message }); - - const results: Array<{ transaction_id: string; ok: boolean; error?: string }> = []; - - for (const row of expired ?? []) { - const result = await releaseEscrow(row.transaction_id, supabase); - results.push({ transaction_id: row.transaction_id, ...result }); - console.log(`auto-release ${row.transaction_id}: ${result.ok ? "OK" : result.error}`); - } - - return resp(200, { released: results.length, results }); -} - -async function handleResolveDispute(req: Request): Promise { - // Admin only — validate service_role key - const adminKey = req.headers.get("x-supabase-admin-key"); - if (adminKey !== supabaseServiceKey) { - return resp(401, { error: "Admin authorization required" }); - } - - const { transaction_id, action } = await req.json(); - if (!transaction_id || !["release", "refund"].includes(action)) { - return resp(400, { error: "transaction_id and action ('release'|'refund') required" }); - } - - const supabase = adminClient(); - const now = new Date().toISOString(); - - if (action === "release") { - const result = await releaseEscrow(transaction_id, supabase); - return result.ok - ? resp(200, { ok: true, action: "released" }) - : resp(500, { error: result.error }); - } - - // action === "refund" - await supabase - .from("escrow_transactions") - .update({ status: "refunded", updated_at: now }) - .eq("transaction_id", transaction_id); - - await supabase - .from("transactions") - .update({ status: "failed" }) - .eq("id", transaction_id); - - return resp(200, { ok: true, action: "refunded" }); -} - -// --------------------------------------------------------------------------- -// Entry point -// --------------------------------------------------------------------------- - -function resp(status: number, body: unknown): Response { - return new Response(JSON.stringify(body), { - status, - headers: { "Content-Type": "application/json" }, - }); -} - -Deno.serve(async (req: Request) => { - try { - const { action } = await req.clone().json().catch(() => ({ action: null })); - - switch (action) { - case "release": - return await handleRelease(req); - case "dispute": - return await handleDispute(req); - case "auto-release-expired": - return await handleAutoReleaseExpired(req); - case "resolve-dispute": - return await handleResolveDispute(req); - default: - return resp(400, { - error: "Unknown action. Valid: release | dispute | auto-release-expired | resolve-dispute", - }); - } - } catch (err) { - console.error("process-escrow unhandled error:", err); - return resp(500, { error: String(err) }); - } -}); diff --git a/supabase/migrations/20260602130000_escrow_payment_flow.sql b/supabase/migrations/20260602130000_escrow_payment_flow.sql deleted file mode 100644 index 1921450..0000000 --- a/supabase/migrations/20260602130000_escrow_payment_flow.sql +++ /dev/null @@ -1,98 +0,0 @@ --- ============================================================ --- Priority 9: Escrow Payment Flow --- Migration: 20260602130000_escrow_payment_flow.sql --- ============================================================ - --- 1. Immutable helper function required for GENERATED column on TIMESTAMPTZ --- (PostgreSQL rejects non-immutable expressions in generated columns; --- this wrapper is declared IMMUTABLE so the planner accepts it.) -CREATE OR REPLACE FUNCTION public.add_48_hours(t TIMESTAMPTZ) -RETURNS TIMESTAMPTZ -LANGUAGE SQL IMMUTABLE AS $$ - SELECT t + INTERVAL '48 hours'; -$$; - --- 2. Create escrow_transactions table -CREATE TABLE IF NOT EXISTS public.escrow_transactions ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - transaction_id UUID NOT NULL REFERENCES public.transactions(id) ON DELETE CASCADE, - status TEXT NOT NULL DEFAULT 'held' - CHECK (status IN ('held', 'released', 'refunded', 'disputed')), - dispute_reason TEXT, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - release_deadline TIMESTAMP WITH TIME ZONE - GENERATED ALWAYS AS (public.add_48_hours(created_at)) STORED -); - --- 3. Performance indexes -CREATE INDEX IF NOT EXISTS idx_escrow_transaction_id ON public.escrow_transactions (transaction_id); -CREATE INDEX IF NOT EXISTS idx_escrow_status ON public.escrow_transactions (status); -CREATE INDEX IF NOT EXISTS idx_escrow_release_deadline ON public.escrow_transactions (release_deadline) - WHERE status = 'held'; - --- 4. updated_at auto-refresh trigger -CREATE OR REPLACE FUNCTION public.set_escrow_updated_at() -RETURNS TRIGGER LANGUAGE plpgsql AS $$ -BEGIN - NEW.updated_at = NOW(); - RETURN NEW; -END; -$$; - -DROP TRIGGER IF EXISTS trg_escrow_updated_at ON public.escrow_transactions; -CREATE TRIGGER trg_escrow_updated_at - BEFORE UPDATE ON public.escrow_transactions - FOR EACH ROW EXECUTE FUNCTION public.set_escrow_updated_at(); - --- 5. Row-Level Security -ALTER TABLE public.escrow_transactions ENABLE ROW LEVEL SECURITY; - --- Buyers and sellers can view their own escrow records -DROP POLICY IF EXISTS "escrow_select_parties" ON public.escrow_transactions; -CREATE POLICY "escrow_select_parties" - ON public.escrow_transactions FOR SELECT - USING ( - EXISTS ( - SELECT 1 FROM public.transactions t - WHERE t.id = escrow_transactions.transaction_id - AND (t.buyer_id = auth.uid() OR t.seller_id = auth.uid()) - ) - ); - --- Only the buyer can dispute or release (INSERT not needed — webhook inserts via service_role) -DROP POLICY IF EXISTS "escrow_update_buyer" ON public.escrow_transactions; -CREATE POLICY "escrow_update_buyer" - ON public.escrow_transactions FOR UPDATE - USING ( - EXISTS ( - SELECT 1 FROM public.transactions t - WHERE t.id = escrow_transactions.transaction_id - AND t.buyer_id = auth.uid() - ) - ); - --- 6. Enable pg_net (required for pg_cron HTTP calls) -CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions; - --- 7. Schedule hourly pg_cron job to trigger auto-release of expired escrows --- The job uses the broadcast_secret from app_secrets for authorization. --- Runs at minute 0 of every hour (0 * * * *). -SELECT cron.unschedule('auto-release-escrows-job') WHERE EXISTS ( - SELECT 1 FROM cron.job WHERE jobname = 'auto-release-escrows-job' -); - -SELECT cron.schedule( - 'auto-release-escrows-job', - '0 * * * *', - $$ - SELECT public.http_post( - url := 'https://jacnsvcwmhoicuuzmrmr.supabase.co/functions/v1/process-escrow', - headers := jsonb_build_object( - 'Content-Type', 'application/json', - 'x-cron-secret', (SELECT value FROM public.app_secrets WHERE key = 'broadcast_secret' LIMIT 1) - ), - body := '{"action":"auto-release-expired"}'::jsonb - ); - $$ -); diff --git a/supabase/migrations/20260602224500_update_transactions_status_check.sql b/supabase/migrations/20260602224500_update_transactions_status_check.sql deleted file mode 100644 index 17cf6f2..0000000 --- a/supabase/migrations/20260602224500_update_transactions_status_check.sql +++ /dev/null @@ -1,6 +0,0 @@ --- Drop existing status check constraint -ALTER TABLE public.transactions DROP CONSTRAINT IF EXISTS transactions_status_check; - --- Add updated status check constraint supporting 'held' and 'disputed' -ALTER TABLE public.transactions ADD CONSTRAINT transactions_status_check - CHECK (status IN ('pending', 'successful', 'failed', 'held', 'disputed')); diff --git a/supabase/migrations/20260611180000_fintech_architecture_fixes.sql b/supabase/migrations/20260611180000_fintech_architecture_fixes.sql deleted file mode 100644 index 28767fe..0000000 --- a/supabase/migrations/20260611180000_fintech_architecture_fixes.sql +++ /dev/null @@ -1,90 +0,0 @@ --- ============================================================ --- Fintech Architecture Fixes --- Migration: 20260611180000_fintech_architecture_fixes.sql --- ============================================================ - --- 1. Extend Auto-Release from 48h to 5 days --- First, drop the generated column that depends on add_48_hours -ALTER TABLE public.escrow_transactions DROP COLUMN IF EXISTS release_deadline; - --- Drop the old helper function -DROP FUNCTION IF EXISTS public.add_48_hours(TIMESTAMPTZ); - --- Create new helper function for 5 days -CREATE OR REPLACE FUNCTION public.add_5_days(t TIMESTAMPTZ) -RETURNS TIMESTAMPTZ -LANGUAGE SQL IMMUTABLE AS $$ - SELECT t + INTERVAL '5 days'; -$$; - --- Re-add release_deadline column with 5 days calculation -ALTER TABLE public.escrow_transactions -ADD COLUMN release_deadline TIMESTAMP WITH TIME ZONE -GENERATED ALWAYS AS (public.add_5_days(created_at)) STORED; - --- 2. Update status check constraint on transactions table -ALTER TABLE public.transactions DROP CONSTRAINT IF EXISTS transactions_status_check; -ALTER TABLE public.transactions ADD CONSTRAINT transactions_status_check - CHECK (status IN ('pending', 'pending_payment', 'successful', 'failed', 'held', 'disputed')); - --- 3. Create fapshi_audit_logs table -CREATE TABLE IF NOT EXISTS public.fapshi_audit_logs ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - transaction_id UUID REFERENCES public.transactions(id) ON DELETE SET NULL, - endpoint TEXT NOT NULL, - request_payload JSONB, - response_payload JSONB, - status_code INTEGER, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); - --- Enable RLS for the audit logs -ALTER TABLE public.fapshi_audit_logs ENABLE ROW LEVEL SECURITY; - --- 4. Store Project URL as Vault Secret -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM vault.decrypted_secrets WHERE name = 'app.supabase_url') THEN - PERFORM vault.create_secret('https://jacnsvcwmhoicuuzmrmr.supabase.co', 'app.supabase_url', 'Supabase Project URL'); - END IF; -END $$; - --- 5. Re-schedule auto-release-escrows-job (using net.http_post & vault secret) -SELECT cron.unschedule('auto-release-escrows-job') WHERE EXISTS ( - SELECT 1 FROM cron.job WHERE jobname = 'auto-release-escrows-job' -); - -SELECT cron.schedule( - 'auto-release-escrows-job', - '0 * * * *', - $$ - SELECT net.http_post( - url := (SELECT decrypted_secret FROM vault.decrypted_secrets WHERE name = 'app.supabase_url' LIMIT 1) || '/functions/v1/process-escrow', - headers := jsonb_build_object( - 'Content-Type', 'application/json', - 'x-cron-secret', (SELECT value FROM public.app_secrets WHERE key = 'broadcast_secret' LIMIT 1) - ), - body := '{"action":"auto-release-expired"}'::jsonb - ); - $$ -); - --- 6. Schedule new fapshi-polling-job (every 5 minutes) -SELECT cron.unschedule('fapshi-polling-job') WHERE EXISTS ( - SELECT 1 FROM cron.job WHERE jobname = 'fapshi-polling-job' -); - -SELECT cron.schedule( - 'fapshi-polling-job', - '*/5 * * * *', - $$ - SELECT net.http_post( - url := (SELECT decrypted_secret FROM vault.decrypted_secrets WHERE name = 'app.supabase_url' LIMIT 1) || '/functions/v1/fapshi-polling', - headers := jsonb_build_object( - 'Content-Type', 'application/json', - 'x-cron-secret', (SELECT value FROM public.app_secrets WHERE key = 'broadcast_secret' LIMIT 1) - ), - body := '{}'::jsonb - ); - $$ -); diff --git a/test.txt b/test.txt deleted file mode 100644 index 9daeafb..0000000 --- a/test.txt +++ /dev/null @@ -1 +0,0 @@ -test diff --git a/landingPage/.gitignore b/web/.gitignore similarity index 100% rename from landingPage/.gitignore rename to web/.gitignore diff --git a/landingPage/.npmrc b/web/.npmrc similarity index 100% rename from landingPage/.npmrc rename to web/.npmrc diff --git a/landingPage/check_db.py b/web/check_db.py similarity index 100% rename from landingPage/check_db.py rename to web/check_db.py diff --git a/landingPage/check_supabase_fast.py b/web/check_supabase_fast.py similarity index 100% rename from landingPage/check_supabase_fast.py rename to web/check_supabase_fast.py diff --git a/landingPage/check_tx.js b/web/check_tx.js similarity index 100% rename from landingPage/check_tx.js rename to web/check_tx.js diff --git a/landingPage/jsconfig.json b/web/jsconfig.json similarity index 100% rename from landingPage/jsconfig.json rename to web/jsconfig.json diff --git a/landingPage/package-lock.json b/web/package-lock.json similarity index 100% rename from landingPage/package-lock.json rename to web/package-lock.json diff --git a/landingPage/package.json b/web/package.json similarity index 100% rename from landingPage/package.json rename to web/package.json diff --git a/landingPage/src/app.css b/web/src/app.css similarity index 100% rename from landingPage/src/app.css rename to web/src/app.css diff --git a/landingPage/src/app.d.ts b/web/src/app.d.ts similarity index 100% rename from landingPage/src/app.d.ts rename to web/src/app.d.ts diff --git a/landingPage/src/app.html b/web/src/app.html similarity index 100% rename from landingPage/src/app.html rename to web/src/app.html diff --git a/landingPage/src/lib/assets/Founder.jpg b/web/src/lib/assets/Founder.jpg similarity index 100% rename from landingPage/src/lib/assets/Founder.jpg rename to web/src/lib/assets/Founder.jpg diff --git a/landingPage/src/lib/assets/favicon.svg b/web/src/lib/assets/favicon.svg similarity index 100% rename from landingPage/src/lib/assets/favicon.svg rename to web/src/lib/assets/favicon.svg diff --git a/landingPage/src/lib/assets/logo.png b/web/src/lib/assets/logo.png similarity index 100% rename from landingPage/src/lib/assets/logo.png rename to web/src/lib/assets/logo.png diff --git a/landingPage/src/lib/assets/screenshot.png b/web/src/lib/assets/screenshot.png similarity index 100% rename from landingPage/src/lib/assets/screenshot.png rename to web/src/lib/assets/screenshot.png diff --git a/landingPage/src/lib/components/AppShowcase.svelte b/web/src/lib/components/AppShowcase.svelte similarity index 100% rename from landingPage/src/lib/components/AppShowcase.svelte rename to web/src/lib/components/AppShowcase.svelte diff --git a/landingPage/src/lib/components/Features.svelte b/web/src/lib/components/Features.svelte similarity index 100% rename from landingPage/src/lib/components/Features.svelte rename to web/src/lib/components/Features.svelte diff --git a/landingPage/src/lib/components/Footer.svelte b/web/src/lib/components/Footer.svelte similarity index 100% rename from landingPage/src/lib/components/Footer.svelte rename to web/src/lib/components/Footer.svelte diff --git a/landingPage/src/lib/components/Founder.svelte b/web/src/lib/components/Founder.svelte similarity index 100% rename from landingPage/src/lib/components/Founder.svelte rename to web/src/lib/components/Founder.svelte diff --git a/landingPage/src/lib/components/Hero.svelte b/web/src/lib/components/Hero.svelte similarity index 100% rename from landingPage/src/lib/components/Hero.svelte rename to web/src/lib/components/Hero.svelte diff --git a/landingPage/src/lib/components/HowItWorks.svelte b/web/src/lib/components/HowItWorks.svelte similarity index 100% rename from landingPage/src/lib/components/HowItWorks.svelte rename to web/src/lib/components/HowItWorks.svelte diff --git a/landingPage/src/lib/components/Navbar.svelte b/web/src/lib/components/Navbar.svelte similarity index 100% rename from landingPage/src/lib/components/Navbar.svelte rename to web/src/lib/components/Navbar.svelte diff --git a/landingPage/src/lib/components/TrustBar.svelte b/web/src/lib/components/TrustBar.svelte similarity index 100% rename from landingPage/src/lib/components/TrustBar.svelte rename to web/src/lib/components/TrustBar.svelte diff --git a/landingPage/src/lib/index.js b/web/src/lib/index.js similarity index 100% rename from landingPage/src/lib/index.js rename to web/src/lib/index.js diff --git a/landingPage/src/lib/links.js b/web/src/lib/links.js similarity index 100% rename from landingPage/src/lib/links.js rename to web/src/lib/links.js diff --git a/landingPage/src/lib/theme.svelte.js b/web/src/lib/theme.svelte.js similarity index 100% rename from landingPage/src/lib/theme.svelte.js rename to web/src/lib/theme.svelte.js diff --git a/landingPage/src/routes/+layout.svelte b/web/src/routes/+layout.svelte similarity index 100% rename from landingPage/src/routes/+layout.svelte rename to web/src/routes/+layout.svelte diff --git a/landingPage/src/routes/+page.svelte b/web/src/routes/+page.svelte similarity index 100% rename from landingPage/src/routes/+page.svelte rename to web/src/routes/+page.svelte diff --git a/landingPage/src/routes/api/webhooks/campay/+server.js b/web/src/routes/api/webhooks/campay/+server.js similarity index 100% rename from landingPage/src/routes/api/webhooks/campay/+server.js rename to web/src/routes/api/webhooks/campay/+server.js diff --git a/landingPage/src/routes/api/webhooks/fapshi-payouts/+server.js b/web/src/routes/api/webhooks/fapshi-payouts/+server.js similarity index 100% rename from landingPage/src/routes/api/webhooks/fapshi-payouts/+server.js rename to web/src/routes/api/webhooks/fapshi-payouts/+server.js diff --git a/landingPage/src/routes/api/webhooks/fapshi/+server.js b/web/src/routes/api/webhooks/fapshi/+server.js similarity index 100% rename from landingPage/src/routes/api/webhooks/fapshi/+server.js rename to web/src/routes/api/webhooks/fapshi/+server.js diff --git a/landingPage/static/favicon.png b/web/static/favicon.png similarity index 100% rename from landingPage/static/favicon.png rename to web/static/favicon.png diff --git a/landingPage/static/robots.txt b/web/static/robots.txt similarity index 100% rename from landingPage/static/robots.txt rename to web/static/robots.txt diff --git a/landingPage/svelte.config.js b/web/svelte.config.js similarity index 100% rename from landingPage/svelte.config.js rename to web/svelte.config.js diff --git a/landingPage/vite.config.js b/web/vite.config.js similarity index 100% rename from landingPage/vite.config.js rename to web/vite.config.js From 5284617a5c465480ae0e889f662df706fa858419 Mon Sep 17 00:00:00 2001 From: Engon Ken Morel Date: Tue, 15 Sep 2026 02:00:27 +0530 Subject: [PATCH 2/4] created initial schema --- backend/schema.sql | 348 +++++++++++++++++++++++++++++++++++ buf.yaml | 11 ++ proto/v1/auth.proto | 121 ++++++++++++ proto/v1/books.proto | 188 +++++++++++++++++++ proto/v1/boosts.proto | 64 +++++++ proto/v1/chat.proto | 108 +++++++++++ proto/v1/common.proto | 18 ++ proto/v1/locations.proto | 42 +++++ proto/v1/notifications.proto | 54 ++++++ proto/v1/purchases.proto | 140 ++++++++++++++ proto/v1/reviews.proto | 52 ++++++ proto/v1/stats.proto | 21 +++ proto/v1/uploads.proto | 57 ++++++ proto/v1/users.proto | 18 ++ proto/v1/wishlist.proto | 46 +++++ 15 files changed, 1288 insertions(+) create mode 100644 backend/schema.sql create mode 100644 buf.yaml create mode 100644 proto/v1/auth.proto create mode 100644 proto/v1/books.proto create mode 100644 proto/v1/boosts.proto create mode 100644 proto/v1/chat.proto create mode 100644 proto/v1/common.proto create mode 100644 proto/v1/locations.proto create mode 100644 proto/v1/notifications.proto create mode 100644 proto/v1/purchases.proto create mode 100644 proto/v1/reviews.proto create mode 100644 proto/v1/stats.proto create mode 100644 proto/v1/uploads.proto create mode 100644 proto/v1/users.proto create mode 100644 proto/v1/wishlist.proto diff --git a/backend/schema.sql b/backend/schema.sql new file mode 100644 index 0000000..85134c5 --- /dev/null +++ b/backend/schema.sql @@ -0,0 +1,348 @@ +create or replace function set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + + +create type location_type as enum ('book', 'meetup'); +create type book_condition as enum ('new', 'like_new', 'good', 'fair', 'poor'); +create type book_picture_type as enum ('front', 'back', 'other'); +create type book_status as enum ('available', 'sold', 'reserved', 'expired', 'removed'); +create type payment_type as enum ('book', 'donation', 'boost'); +create type payment_status as enum ('pending', 'completed', 'failed'); +create type payment_method as enum ('fapshi'); +create type transaction_status as enum ('held', 'released', 'refunded', 'disputed'); +create type verification_document_type as enum ('nationalid', 'schoolid'); + + +-- TODO: Add user kyc verification, method to set notified device +create table if not exists users ( + id uuid primary key default uuidv7(), + email varchar(255), + phone varchar(255) not null, + first_name varchar(32) not null, + last_name varchar(32) not null, + avatar_id uuid references uploads(id) on delete set null, + rating numeric(3,2) not null default 0.00 check (rating between 0 and 5), + verified boolean not null default false, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + deleted_at timestamptz +); + +create or replace trigger trg_users_updated_at + before update on users + for each row execute function set_updated_at(); + +create table if not exists user_sessions ( + session_id uuid primary key default uuidv7(), + user_id uuid not null references users(id) on delete cascade, + refresh_token_hash bytea not null unique, -- sha256 of the opaque refresh token; never store the raw token + expires_at timestamptz not null, -- refresh token expiry + rotated_at timestamptz not null default now(), -- set on every token rotation + fcm_token text, + created_at timestamptz not null default now() +); + +create index if not exists idx_user_sessions_user_id on user_sessions (user_id); + +create table if not exists verification_documents ( + user_id uuid not null references users(id) on delete cascade, + upload_id uuid not null references uploads(id) on delete cascade, + document_type verification_document_type not null, + created_at timestamptz not null default now() +); + + +-- ============================================================================= +-- uploads +-- ============================================================================= + +create table if not exists uploads ( + id uuid primary key default uuidv7(), + storage_key varchar(512) unique not null, + file_name varchar(255) not null, + content_type varchar(100) not null, + size_bytes bigint not null check (size_bytes > 0), + uploaded_by uuid references users(id) on delete set null, + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp +); + +create or replace trigger trg_uploads_updated_at + before update on uploads + for each row execute function set_updated_at(); + +create index if not exists idx_uploads_uploaded_by on uploads (uploaded_by); + + +-- ============================================================================= +-- geo / indexed locations +-- ============================================================================= + +-- too much yes +create table if not exists indexed_locations ( + id uuid primary key default uuidv7(), + type location_type not null, + latitude double precision not null, + longitude double precision not null, + h3_3 bigint not null, -- 274.08km long diameter + h3_4 bigint not null, -- 39.16km long diameter + h3_5 bigint not null, -- 14.79km long diameter + h3_6 bigint not null, -- 05.60km long diameter + h3_7 bigint not null, -- 02.11km long diameter +); + +create index if not exists idx_indexed_locations_h3_3 on indexed_locations (h3_3); +create index if not exists idx_indexed_locations_h3_4 on indexed_locations (h3_4); +create index if not exists idx_indexed_locations_h3_5 on indexed_locations (h3_5); +create index if not exists idx_indexed_locations_h3_6 on indexed_locations (h3_6); +create index if not exists idx_indexed_locations_h3_7 on indexed_locations (h3_7); + +create table if not exists meetup_locations ( + id uuid primary key default uuidv7(), + name text not null, + description text, + location_id uuid not null references indexed_locations(id) on delete cascade, + verified boolean not null default false, + created_at timestamptz not null default now() +); + +create index if not exists idx_meetup_locations_location_id on meetup_locations (location_id); + + +-- ============================================================================= +-- books +-- ============================================================================= + +create table if not exists book_categories ( + id bigserial primary key, + name varchar(63) not null unique + name text +); + +create table if not exists books ( + id uuid primary key default uuidv7(), + seller_id uuid not null references users(id) on delete cascade, + ebook_id uuid not null references uploads(id) on delete set null, + title varchar(255) not null, + author varchar(255) not null, + price integer not null check (price > 0), + condition book_condition not null, + description text, + status book_status not null default 'available', + category bigint not null references book_categories(id) on delete cascade, + refundable boolean not null default false, + swapable boolean not null default false, + boost_expires_at timestamptz not null default now(), + expires_at timestamptz not null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + deleted_at timestamptz, + location uuid references indexed_locations(id) on delete cascade +); + +create or replace trigger trg_books_updated_at + before update on books + for each row execute function set_updated_at(); + +create index if not exists idx_books_seller_id on books (seller_id); +create index if not exists idx_books_status on books (status); +create index if not exists idx_books_category on books (category); +create index if not exists idx_books_location on books (location); + +create table if not exists book_pictures ( + upload_id uuid not null references uploads(id) on delete cascade, + book_id uuid not null references books(id) on delete cascade, + primary key (book_id, upload_id) + + type book_picture_type not null default 'other', +); + +create index if not exists idx_book_pictures_upload_id on book_pictures (upload_id); + + +-- ============================================================================= +-- messaging +-- ============================================================================= + +create table if not exists conversations ( + id uuid primary key default uuidv7(), + book_id uuid not null references books(id) on delete cascade, + user_id uuid not null references users(id) on delete cascade, + created_at timestamptz not null default now(), + deleted_at timestamptz +); + +create index if not exists idx_conversations_book_id on conversations (book_id); +create index if not exists idx_conversations_user_id on conversations (user_id); + +create table if not exists conversation_messages ( + id uuid primary key default uuidv7(), + user_id uuid not null references users(id) on delete cascade, + conversation_id uuid not null references conversations(id) on delete cascade, + content text not null, + attachment uuid references uploads(id) on delete set null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + deleted_at timestamptz +); + +create or replace trigger trg_conversation_messages_updated_at + before update on conversation_messages + for each row execute function set_updated_at(); + +create index if not exists idx_conversation_messages_conversation_id + on conversation_messages (conversation_id, created_at); +create index if not exists idx_conversation_messages_user_id on conversation_messages (user_id); + + +-- ============================================================================= +-- wishlist +-- ============================================================================= + +create table if not exists wishlist_items ( + user_id uuid not null references users(id) on delete cascade, + book_id uuid not null references books(id) on delete cascade, + created_at timestamptz not null default now(), + primary key (user_id, book_id) +); + +create index if not exists idx_wishlist_items_book_id on wishlist_items (book_id); + + +-- ============================================================================= +-- notifications +-- ============================================================================= + +create table if not exists notification_templates ( + id uuid primary key, + parameters jsonb not null default '{}' +); + +create table if not exists notification_template_translations ( + template_id uuid not null references notification_templates(id) on delete cascade, + lang varchar(2) not null, + format text not null, + primary key (template_id, lang) +); + +create table if not exists notification_bodies ( + id uuid primary key default uuidv7(), + template_id uuid not null references notification_templates(id) on delete cascade, + template_arguments jsonb not null default '{}' +); + +create index if not exists idx_notification_bodies_template_id on notification_bodies (template_id); + +create table if not exists notifications ( + id uuid primary key default uuidv7(), + user_id uuid references users(id) on delete cascade, + body_id uuid references notification_bodies(id) on delete cascade, + template_arguments jsonb not null default '{}', + read_at timestamptz, + created_at timestamptz not null default now() +); + +create index if not exists idx_notifications_user_id on notifications (user_id, created_at desc); + +-- ============================================================================= +-- feedback +-- ============================================================================= + +create table if not exists reviews ( + id uuid primary key default uuidv7(), + author_id uuid not null references users(id) on delete cascade, + rating numeric(3,2) check (rating between 1 and 5), + content text, + created_at timestamptz not null default now() +); + +-- todo author-reviews, book-reviews(maybe), others +create index if not exists idx_reviews_author_id on reviews (author_id); + + +-- ============================================================================= +-- payments and transactions +-- ============================================================================= + +create table if not exists payment_intents ( + id uuid primary key default uuidv7(), + user_id uuid not null references users(id) on delete cascade, + method payment_method not null, + amount integer not null, + status payment_status not null default 'pending', + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +create or replace trigger trg_payment_intents_updated_at + before update on payment_intents + for each row execute function set_updated_at(); + +create index if not exists idx_payment_intents_user_id on payment_intents (user_id); + +create table if not exists payments ( + intent_id uuid primary key references payment_intents(id), + platform_transaction_reference text not null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +create or replace trigger trg_payments_updated_at + before update on payments + for each row execute function set_updated_at(); + +create table if not exists transactions ( + payment_id uuid primary key references payments(intent_id) on delete cascade, + recipient uuid not null references users(id) on delete cascade, + transaction_status transaction_status not null default 'held', + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + refunded_at timestamptz, + deleted_at timestamptz +); + +create or replace trigger trg_transactions_updated_at + before update on transactions + for each row execute function set_updated_at(); + +create index if not exists idx_transactions_recipient on transactions (recipient); + + +-- ============================================================================= +-- payment types +-- ============================================================================= + +create table if not exists boosts ( + payment_id uuid primary key references payments(intent_id) on delete cascade, + book_id uuid not null references books(id) on delete cascade, + created_at timestamptz not null default now(), + expires_at timestamptz not null +); + +create index if not exists idx_boosts_book_id on boosts (book_id); + +create table if not exists donations ( + payment_id uuid primary key references payments(intent_id) on delete cascade, + user_id uuid references users(id) on delete set null, + message text, + created_at timestamptz not null default now() +); + +create index if not exists idx_donations_user_id on donations (user_id); + +create table if not exists book_purchases ( + transaction_id uuid primary key references transactions(payment_id) on delete cascade, + book_id uuid not null references books(id) on delete cascade, + meetup_location uuid references meetup_locations(id) on delete set null, + confirmed boolean not null default false, + created_at timestamptz not null default now() +); + +create index if not exists idx_book_purchases_book_id on book_purchases (book_id); diff --git a/buf.yaml b/buf.yaml new file mode 100644 index 0000000..9223dce --- /dev/null +++ b/buf.yaml @@ -0,0 +1,11 @@ +version: v2 +modules: + - path: . +lint: + use: + - STANDARD + except: + - PACKAGE_DIRECTORY_MATCH +breaking: + use: + - FILE diff --git a/proto/v1/auth.proto b/proto/v1/auth.proto new file mode 100644 index 0000000..7887581 --- /dev/null +++ b/proto/v1/auth.proto @@ -0,0 +1,121 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; + +// Full user record as seen by the user themselves (maps to the users table). +message User { + string id = 1; + string email = 2; + string phone = 3; + string first_name = 4; + string last_name = 5; + string avatar_url = 6; + double rating = 7; + bool verified = 8; + google.protobuf.Timestamp created_at = 9; + google.protobuf.Timestamp updated_at = 10; +} + +message Session { + string session_id = 1; + User user = 2; + // Short-lived stateless access token (JWT) for authorizing API calls. + string access_token = 3; + // Opaque, single-use secret used to obtain new access tokens. Sent only + // when the session is created or refreshed; never returned on reads. + string refresh_token = 4; + google.protobuf.Timestamp access_token_expires_at = 5; + google.protobuf.Timestamp expires_at = 6; +} + +message SignUpRequest { + string email = 1; + string phone = 2; + string password = 3; + string first_name = 4; + string last_name = 5; +} + +message SignUpResponse { + Session session = 1; +} + +message SignInRequest { + oneof identifier { + string email = 1; + string phone = 2; + } + string password = 3; +} + +message SignInResponse { + Session session = 1; +} + +message SignInWithGoogleRequest { + string id_token = 1; +} + +message SignInWithGoogleResponse { + Session session = 1; +} + +message RefreshSessionRequest { + // The opaque refresh token issued with the current session. + string refresh_token = 1; +} + +message RefreshSessionResponse { + // New session with a fresh access token and a rotated refresh token; + // the presented refresh token is invalidated. + Session session = 1; +} + +message SignOutRequest {} + +message SignOutResponse {} + +message GetCurrentUserRequest {} + +message GetCurrentUserResponse { + User user = 1; +} + +message UpdateCurrentUserRequest { + optional string email = 1; + optional string first_name = 2; + optional string last_name = 3; + optional string avatar_upload_id = 4; +} + +message UpdateCurrentUserResponse { + User user = 1; +} + +message SendPasswordResetRequest { + string email = 1; +} + +message SendPasswordResetResponse {} + +// Registers/updates the FCM token of the device tied to the current session +// (maps to user_sessions.fcm_token). +message SetDeviceTokenRequest { + string fcm_token = 1; +} + +message SetDeviceTokenResponse {} + +service AuthService { + rpc SignUp(SignUpRequest) returns (SignUpResponse); + rpc SignIn(SignInRequest) returns (SignInResponse); + rpc SignInWithGoogle(SignInWithGoogleRequest) returns (SignInWithGoogleResponse); + rpc RefreshSession(RefreshSessionRequest) returns (RefreshSessionResponse); + rpc SignOut(SignOutRequest) returns (SignOutResponse); + rpc GetCurrentUser(GetCurrentUserRequest) returns (GetCurrentUserResponse); + rpc UpdateCurrentUser(UpdateCurrentUserRequest) returns (UpdateCurrentUserResponse); + rpc SendPasswordReset(SendPasswordResetRequest) returns (SendPasswordResetResponse); + rpc SetDeviceToken(SetDeviceTokenRequest) returns (SetDeviceTokenResponse); +} diff --git a/proto/v1/books.proto b/proto/v1/books.proto new file mode 100644 index 0000000..64285e3 --- /dev/null +++ b/proto/v1/books.proto @@ -0,0 +1,188 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; +import "proto/v1/common.proto"; + +enum BookCondition { + BOOK_CONDITION_UNSPECIFIED = 0; + BOOK_CONDITION_NEW = 1; + BOOK_CONDITION_LIKE_NEW = 2; + BOOK_CONDITION_GOOD = 3; + BOOK_CONDITION_FAIR = 4; + BOOK_CONDITION_POOR = 5; +} + +enum BookStatus { + BOOK_STATUS_UNSPECIFIED = 0; + BOOK_STATUS_AVAILABLE = 1; + BOOK_STATUS_SOLD = 2; + BOOK_STATUS_RESERVED = 3; + BOOK_STATUS_EXPIRED = 4; + BOOK_STATUS_REMOVED = 5; +} + +enum BookPictureType { + BOOK_PICTURE_TYPE_UNSPECIFIED = 0; + BOOK_PICTURE_TYPE_FRONT = 1; + BOOK_PICTURE_TYPE_BACK = 2; + BOOK_PICTURE_TYPE_OTHER = 3; +} + +message BookCategory { + int64 id = 1; + string name = 2; +} + +message BookPicture { + string upload_id = 1; + string url = 2; + BookPictureType type = 3; +} + +// Maps to the books table with its seller joined in. +message Book { + string id = 1; + UserSummary seller = 2; + string title = 3; + string author = 4; + int64 price_fcfa = 5; + BookCondition condition = 6; + string description = 7; + BookStatus status = 8; + BookCategory category = 9; + bool refundable = 10; + bool swapable = 11; + repeated BookPicture pictures = 12; + string ebook_id = 13; + google.protobuf.Timestamp boost_expires_at = 14; + google.protobuf.Timestamp expires_at = 15; + google.protobuf.Timestamp created_at = 16; + google.protobuf.Timestamp updated_at = 17; + LatLng location = 18; +} + +message ListCategoriesRequest {} + +message ListCategoriesResponse { + repeated BookCategory categories = 1; +} + +message ListBooksRequest { + string page_token = 1; + int32 page_size = 2; + BookStatus status = 3; + int64 category_id = 4; + // Center for radius-based discovery (uses the indexed_locations H3 columns). + LatLng center = 5; + double radius_km = 6; +} + +message ListBooksResponse { + repeated Book books = 1; + string next_page_token = 2; +} + +message SearchBooksRequest { + string query = 1; + string page_token = 2; + int32 page_size = 3; + int64 category_id = 4; + LatLng center = 5; + double radius_km = 6; +} + +message SearchBooksResponse { + repeated Book books = 1; + string next_page_token = 2; +} + +message GetBookRequest { + string book_id = 1; +} + +message GetBookResponse { + Book book = 1; +} + +message ListBooksBySellerRequest { + string seller_id = 1; + string page_token = 2; + int32 page_size = 3; +} + +message ListBooksBySellerResponse { + repeated Book books = 1; + string next_page_token = 2; +} + +message ListMyBooksRequest { + string page_token = 1; + int32 page_size = 2; + BookStatus status = 3; +} + +message ListMyBooksResponse { + repeated Book books = 1; + string next_page_token = 2; +} + +message CreateBookRequest { + string title = 1; + string author = 2; + int64 price_fcfa = 3; + BookCondition condition = 4; + string description = 5; + int64 category_id = 6; + bool refundable = 7; + bool swapable = 8; + repeated string picture_upload_ids = 9; + map picture_types = 10; + string ebook_upload_id = 11; + LatLng location = 12; + // Listing expiry in days from creation; server assigns a default when unset. + optional int32 expires_in_days = 13; +} + +message CreateBookResponse { + Book book = 1; +} + +message UpdateBookRequest { + string book_id = 1; + optional string title = 2; + optional string author = 3; + optional int64 price_fcfa = 4; + optional BookCondition condition = 5; + optional string description = 6; + optional int64 category_id = 7; + optional bool refundable = 8; + optional bool swapable = 9; + optional BookStatus status = 10; + repeated string picture_upload_ids = 11; + map picture_types = 12; + optional LatLng location = 13; +} + +message UpdateBookResponse { + Book book = 1; +} + +message DeleteBookRequest { + string book_id = 1; +} + +message DeleteBookResponse {} + +service BookService { + rpc ListCategories(ListCategoriesRequest) returns (ListCategoriesResponse); + rpc ListBooks(ListBooksRequest) returns (ListBooksResponse); + rpc SearchBooks(SearchBooksRequest) returns (SearchBooksResponse); + rpc GetBook(GetBookRequest) returns (GetBookResponse); + rpc ListBooksBySeller(ListBooksBySellerRequest) returns (ListBooksBySellerResponse); + rpc ListMyBooks(ListMyBooksRequest) returns (ListMyBooksResponse); + rpc CreateBook(CreateBookRequest) returns (CreateBookResponse); + rpc UpdateBook(UpdateBookRequest) returns (UpdateBookResponse); + rpc DeleteBook(DeleteBookRequest) returns (DeleteBookResponse); +} diff --git a/proto/v1/boosts.proto b/proto/v1/boosts.proto new file mode 100644 index 0000000..0ff107f --- /dev/null +++ b/proto/v1/boosts.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; + +// Maps to the boosts table (payment_type = boost). +message Boost { + string id = 1; + string book_id = 2; + int64 amount_fcfa = 3; + google.protobuf.Timestamp expires_at = 4; + google.protobuf.Timestamp created_at = 5; +} + +message CreateBoostRequest { + string book_id = 1; + int64 amount_fcfa = 2; +} + +message CreateBoostResponse { + Boost boost = 1; + string fapshi_transaction_id = 2; +} + +message GetBoostStatusRequest { + string boost_id = 1; +} + +message GetBoostStatusResponse { + Boost boost = 1; + PaymentOutcome outcome = 2; +} + +message PaymentOutcome { + string status = 1; + string message = 2; +} + +message CreateDonationRequest { + int64 amount_fcfa = 1; + string message = 2; +} + +message Donation { + string id = 1; + int64 amount_fcfa = 2; + string message = 3; + google.protobuf.Timestamp created_at = 4; +} + +message CreateDonationResponse { + Donation donation = 1; + string fapshi_transaction_id = 2; +} + +service BoostService { + rpc CreateBoost(CreateBoostRequest) returns (CreateBoostResponse); + rpc GetBoostStatus(GetBoostStatusRequest) returns (GetBoostStatusResponse); +} + +service DonationService { + rpc CreateDonation(CreateDonationRequest) returns (CreateDonationResponse); +} diff --git a/proto/v1/chat.proto b/proto/v1/chat.proto new file mode 100644 index 0000000..ae14409 --- /dev/null +++ b/proto/v1/chat.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; +import "proto/v1/common.proto"; + +// Maps to conversation_messages. +message Message { + string id = 1; + string conversation_id = 2; + string user_id = 3; + string content = 4; + UploadAttachment attachment = 5; + google.protobuf.Timestamp created_at = 6; +} + +message UploadAttachment { + string upload_id = 1; + string url = 2; + string content_type = 3; + string file_name = 4; +} + +// Conversation summary (conversations table + last message + unread count). +message Conversation { + string id = 1; + string book_id = 2; + BookSummary book = 3; + UserSummary other_participant = 4; + string last_message = 5; + google.protobuf.Timestamp last_message_at = 6; + int32 unread_count = 7; +} + +// Lightweight book info for conversation list rows. +message BookSummary { + string id = 1; + string title = 2; + string cover_url = 3; +} + +message ListConversationsRequest { + string page_token = 1; + int32 page_size = 2; +} + +message ListConversationsResponse { + repeated Conversation conversations = 1; + string next_page_token = 2; +} + +message GetOrCreateConversationRequest { + string book_id = 1; +} + +message GetOrCreateConversationResponse { + Conversation conversation = 1; +} + +message ListMessagesRequest { + string conversation_id = 1; + string page_token = 2; + int32 page_size = 3; +} + +message ListMessagesResponse { + repeated Message messages = 1; + string next_page_token = 2; +} + +message SendMessageRequest { + string conversation_id = 1; + string content = 2; + string attachment_upload_id = 3; +} + +message SendMessageResponse { + Message message = 1; +} + +message MarkMessagesReadRequest { + string conversation_id = 1; +} + +message MarkMessagesReadResponse {} + +// Server-streamed conversation events for real-time updates. +message StreamConversationsRequest { + // Client cursor: only events for changes after this timestamp are sent. + google.protobuf.Timestamp since = 1; +} + +message StreamConversationsResponse { + oneof event { + Conversation upserted = 1; + Message message_created = 2; + } +} + +service ChatService { + rpc ListConversations(ListConversationsRequest) returns (ListConversationsResponse); + rpc GetOrCreateConversation(GetOrCreateConversationRequest) returns (GetOrCreateConversationResponse); + rpc ListMessages(ListMessagesRequest) returns (ListMessagesResponse); + rpc SendMessage(SendMessageRequest) returns (SendMessageResponse); + rpc MarkMessagesRead(MarkMessagesReadRequest) returns (MarkMessagesReadResponse); + rpc StreamConversations(StreamConversationsRequest) returns (stream StreamConversationsResponse); +} diff --git a/proto/v1/common.proto b/proto/v1/common.proto new file mode 100644 index 0000000..7c6c409 --- /dev/null +++ b/proto/v1/common.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package bookbridge.v1; + +message LatLng { + double latitude = 1; + double longitude = 2; +} + +// Public-facing user info embedded in books, conversations, reviews, etc. +message UserSummary { + string id = 1; + string first_name = 2; + string last_name = 3; + string avatar_url = 4; + double rating = 5; + bool verified = 6; +} diff --git a/proto/v1/locations.proto b/proto/v1/locations.proto new file mode 100644 index 0000000..db90bbc --- /dev/null +++ b/proto/v1/locations.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; +import "proto/v1/common.proto"; + +// Maps to the meetup_locations table. +message MeetupLocation { + string id = 1; + string name = 2; + string description = 3; + bool verified = 4; + LatLng location = 5; + google.protobuf.Timestamp created_at = 6; +} + +message ListMeetupLocationsRequest { + // When set, only return locations within radius of the center. + LatLng center = 1; + double radius_km = 2; + string page_token = 3; + int32 page_size = 4; +} + +message ListMeetupLocationsResponse { + repeated MeetupLocation locations = 1; + string next_page_token = 2; +} + +message GetMeetupLocationRequest { + string location_id = 1; +} + +message GetMeetupLocationResponse { + MeetupLocation location = 1; +} + +service MeetupLocationService { + rpc ListMeetupLocations(ListMeetupLocationsRequest) returns (ListMeetupLocationsResponse); + rpc GetMeetupLocation(GetMeetupLocationRequest) returns (GetMeetupLocationResponse); +} diff --git a/proto/v1/notifications.proto b/proto/v1/notifications.proto new file mode 100644 index 0000000..6115170 --- /dev/null +++ b/proto/v1/notifications.proto @@ -0,0 +1,54 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/struct.proto"; + +// Maps to notifications joined with notification_bodies / template translations. +message Notification { + string id = 1; + string title = 2; + string body = 3; + string type = 4; + google.protobuf.Struct data = 5; + google.protobuf.Timestamp read_at = 6; + google.protobuf.Timestamp created_at = 7; +} + +message ListNotificationsRequest { + string page_token = 1; + int32 page_size = 2; + bool unread_only = 3; +} + +message ListNotificationsResponse { + repeated Notification notifications = 1; + string next_page_token = 2; +} + +message MarkNotificationReadRequest { + string notification_id = 1; +} + +message MarkNotificationReadResponse {} + +message MarkAllNotificationsReadRequest {} + +message MarkAllNotificationsReadResponse {} + +// Server-streamed notifications for real-time updates. +message StreamNotificationsRequest { + google.protobuf.Timestamp since = 1; +} + +message StreamNotificationsResponse { + Notification notification = 1; +} + +service NotificationService { + rpc ListNotifications(ListNotificationsRequest) returns (ListNotificationsResponse); + rpc MarkNotificationRead(MarkNotificationReadRequest) returns (MarkNotificationReadResponse); + rpc MarkAllNotificationsRead(MarkAllNotificationsReadRequest) returns (MarkAllNotificationsReadResponse); + rpc StreamNotifications(StreamNotificationsRequest) returns (stream StreamNotificationsResponse); +} diff --git a/proto/v1/purchases.proto b/proto/v1/purchases.proto new file mode 100644 index 0000000..bfeb398 --- /dev/null +++ b/proto/v1/purchases.proto @@ -0,0 +1,140 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; +import "proto/v1/locations.proto"; + +// Payment methods supported by the platform (Fapshi today). +enum PaymentMethod { + PAYMENT_METHOD_UNSPECIFIED = 0; + PAYMENT_METHOD_FAPSHI = 1; +} + +enum PaymentStatus { + PAYMENT_STATUS_UNSPECIFIED = 0; + PAYMENT_STATUS_PENDING = 1; + PAYMENT_STATUS_COMPLETED = 2; + PAYMENT_STATUS_FAILED = 3; +} + +enum TransactionStatus { + TRANSACTION_STATUS_UNSPECIFIED = 0; + TRANSACTION_STATUS_HELD = 1; + TRANSACTION_STATUS_RELEASED = 2; + TRANSACTION_STATUS_REFUNDED = 3; + TRANSACTION_STATUS_DISPUTED = 4; +} + +// What the payment is for (maps to payment_type enum in the schema). +enum PaymentPurpose { + PAYMENT_PURPOSE_UNSPECIFIED = 0; + PAYMENT_PURPOSE_BOOK = 1; + PAYMENT_PURPOSE_DONATION = 2; + PAYMENT_PURPOSE_BOOST = 3; +} + +// Maps to payment_intents + payments. +message Payment { + string id = 1; + PaymentMethod method = 2; + int64 amount_fcfa = 3; + PaymentStatus status = 4; + PaymentPurpose purpose = 5; + string platform_transaction_reference = 6; + google.protobuf.Timestamp created_at = 7; + google.protobuf.Timestamp updated_at = 8; +} + +// Maps to book_purchases (escrow flow). +message Purchase { + string id = 1; + string transaction_id = 2; + BookPurchaseDetails book = 3; + string buyer_id = 4; + TransactionStatus status = 5; + bool confirmed = 6; + google.protobuf.Timestamp created_at = 7; +} + +message BookPurchaseDetails { + string book_id = 1; + string title = 2; + string cover_url = 3; + int64 price_fcfa = 4; + MeetupLocation meetup_location = 5; +} + +message CreateBookPurchaseRequest { + string book_id = 1; + optional string meetup_location_id = 2; +} + +message CreateBookPurchaseResponse { + Purchase purchase = 1; + // Fapshi session identifier to poll for confirmation. + string fapshi_transaction_id = 2; +} + +message GetPurchaseRequest { + string purchase_id = 1; +} + +message GetPurchaseResponse { + Purchase purchase = 1; +} + +message ListMyPurchasesRequest { + string page_token = 1; + int32 page_size = 2; +} + +message ListMyPurchasesResponse { + repeated Purchase purchases = 1; + string next_page_token = 2; +} + +message ListMySalesRequest { + string page_token = 1; + int32 page_size = 2; +} + +message Sale { + string id = 1; + string transaction_id = 2; + BookPurchaseDetails book = 3; + string buyer_id = 4; + TransactionStatus status = 5; + google.protobuf.Timestamp created_at = 6; +} + +message ListMySalesResponse { + repeated Sale sales = 1; + string next_page_token = 2; +} + +message ConfirmReceiptRequest { + string purchase_id = 1; +} + +message ConfirmReceiptResponse { + Purchase purchase = 1; +} + +message DisputePurchaseRequest { + string purchase_id = 1; + string reason = 2; +} + +message DisputePurchaseResponse { + Purchase purchase = 1; +} + +service PurchaseService { + rpc CreateBookPurchase(CreateBookPurchaseRequest) returns (CreateBookPurchaseResponse); + rpc GetPurchase(GetPurchaseRequest) returns (GetPurchaseResponse); + rpc ListMyPurchases(ListMyPurchasesRequest) returns (ListMyPurchasesResponse); + rpc ListMySales(ListMySalesRequest) returns (ListMySalesResponse); + rpc ConfirmReceipt(ConfirmReceiptRequest) returns (ConfirmReceiptResponse); + rpc DisputePurchase(DisputePurchaseRequest) returns (DisputePurchaseResponse); +} diff --git a/proto/v1/reviews.proto b/proto/v1/reviews.proto new file mode 100644 index 0000000..fa062cb --- /dev/null +++ b/proto/v1/reviews.proto @@ -0,0 +1,52 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; +import "proto/v1/common.proto"; + +// Maps to the reviews table. +message Review { + string id = 1; + UserSummary author = 2; + string reviewee_id = 3; + int32 rating = 4; + string content = 5; + google.protobuf.Timestamp created_at = 6; +} + +message CreateReviewRequest { + string reviewee_id = 1; + string transaction_id = 2; + int32 rating = 3; + string content = 4; +} + +message CreateReviewResponse { + Review review = 1; +} + +message ListUserReviewsRequest { + string user_id = 1; + string page_token = 2; + int32 page_size = 3; +} + +message ListUserReviewsResponse { + repeated Review reviews = 1; + string next_page_token = 2; +} + +message HasReviewedTransactionRequest { + string transaction_id = 1; +} + +message HasReviewedTransactionResponse { + bool has_reviewed = 1; +} + +service ReviewService { + rpc CreateReview(CreateReviewRequest) returns (CreateReviewResponse); + rpc ListUserReviews(ListUserReviewsRequest) returns (ListUserReviewsResponse); + rpc HasReviewedTransaction(HasReviewedTransactionRequest) returns (HasReviewedTransactionResponse); +} diff --git a/proto/v1/stats.proto b/proto/v1/stats.proto new file mode 100644 index 0000000..0cfd576 --- /dev/null +++ b/proto/v1/stats.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package bookbridge.v1; + +// Aggregate platform statistics for the impact screen. +message PlatformStats { + int64 total_books_circulated = 1; + int64 total_students_reached = 2; + int64 total_money_saved_fcfa = 3; + double total_co2_avoided_kg = 4; +} + +message GetPlatformStatsRequest {} + +message GetPlatformStatsResponse { + PlatformStats stats = 1; +} + +service StatsService { + rpc GetPlatformStats(GetPlatformStatsRequest) returns (GetPlatformStatsResponse); +} diff --git a/proto/v1/uploads.proto b/proto/v1/uploads.proto new file mode 100644 index 0000000..2a61018 --- /dev/null +++ b/proto/v1/uploads.proto @@ -0,0 +1,57 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "google/protobuf/timestamp.proto"; + +// Maps to the uploads table. +message Upload { + string id = 1; + string storage_key = 2; + string file_name = 3; + string content_type = 4; + int64 size_bytes = 5; + string url = 6; + google.protobuf.Timestamp created_at = 7; +} + +message CreateUploadRequest { + string file_name = 1; + string content_type = 2; + int64 size_bytes = 3; +} + +message CreateUploadResponse { + Upload upload = 1; + // Pre-signed PUT target the client uploads the bytes to. + string upload_url = 2; +} + +message CompleteUploadRequest { + string upload_id = 1; +} + +message CompleteUploadResponse { + Upload upload = 1; +} + +message GetUploadRequest { + string upload_id = 1; +} + +message GetUploadResponse { + Upload upload = 1; +} + +message DeleteUploadRequest { + string upload_id = 1; +} + +message DeleteUploadResponse {} + +service UploadService { + rpc CreateUpload(CreateUploadRequest) returns (CreateUploadResponse); + rpc CompleteUpload(CompleteUploadRequest) returns (CompleteUploadResponse); + rpc GetUpload(GetUploadRequest) returns (GetUploadResponse); + rpc DeleteUpload(DeleteUploadRequest) returns (DeleteUploadResponse); +} diff --git a/proto/v1/users.proto b/proto/v1/users.proto new file mode 100644 index 0000000..51fc947 --- /dev/null +++ b/proto/v1/users.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "proto/v1/common.proto"; + +message GetUserRequest { + string user_id = 1; +} + +message GetUserResponse { + UserSummary user = 1; +} + +service UserService { + // Fetch a user's public profile (e.g. a seller's page). + rpc GetUser(GetUserRequest) returns (GetUserResponse); +} diff --git a/proto/v1/wishlist.proto b/proto/v1/wishlist.proto new file mode 100644 index 0000000..24ca634 --- /dev/null +++ b/proto/v1/wishlist.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; + +package bookbridge.v1; + +import "proto/v1/books.proto"; + +message ListWishlistRequest { + string page_token = 1; + int32 page_size = 2; +} + +message ListWishlistResponse { + repeated Book books = 1; + string next_page_token = 2; +} + +message AddBookToWishlistRequest { + string book_id = 1; +} + +message AddBookToWishlistResponse { + bool added = 1; +} + +message RemoveBookFromWishlistRequest { + string book_id = 1; +} + +message RemoveBookFromWishlistResponse { + bool removed = 1; +} + +message IsBookInWishlistRequest { + string book_id = 1; +} + +message IsBookInWishlistResponse { + bool is_favorite = 1; +} + +service WishlistService { + rpc ListWishlist(ListWishlistRequest) returns (ListWishlistResponse); + rpc AddBookToWishlist(AddBookToWishlistRequest) returns (AddBookToWishlistResponse); + rpc RemoveBookFromWishlist(RemoveBookFromWishlistRequest) returns (RemoveBookFromWishlistResponse); + rpc IsBookInWishlist(IsBookInWishlistRequest) returns (IsBookInWishlistResponse); +} From 5f592869522450742916495b99cf8128ea907f6d Mon Sep 17 00:00:00 2001 From: ken-morel Date: Wed, 16 Sep 2026 13:10:18 +0530 Subject: [PATCH 3/4] feat(backend): Implemented base services. Needs review Signed-off-by: ken-morel Change-Id: I5f27a4f2720da75dc9234a258d74f6c96a6a6964 --- .gitignore | 1 + app/web/mobile-server.js | 80 + backend/.gitignore | 7 + backend/Cargo.lock | 3078 + backend/Cargo.toml | 29 + backend/diesel.toml | 9 + .../down.sql | 2 + .../up.sql | 18 + .../down.sql | 37 + .../up.sql | 352 + backend/rust-toolchain.toml | 2 + backend/schema.sql | 122 +- backend/src/config.rs | 86 + backend/src/db.rs | 62 + backend/src/fapshi.rs | 191 + backend/src/jwt.rs | 85 + backend/src/main.rs | 78 +- backend/src/middleware/auth.rs | 139 + backend/src/middleware/logging.rs | 138 + backend/src/middleware/mod.rs | 5 + backend/src/models.rs | 783 + backend/src/proto/buf/bookbridge.v1.rs | 67372 ++++++++++++++++ backend/src/proto/mod.rs | 21 + backend/src/proto/svc/bookbridge.v1.rs | 12893 +++ backend/src/schema.rs | 384 + backend/src/services/mod.rs | 1 + backend/src/services/v1/auth.rs | 408 + backend/src/services/v1/books.rs | 568 + backend/src/services/v1/boosts.rs | 291 + backend/src/services/v1/chat.rs | 330 + backend/src/services/v1/helpers.rs | 108 + backend/src/services/v1/locations.rs | 108 + backend/src/services/v1/mod.rs | 39 + backend/src/services/v1/notifications.rs | 141 + backend/src/services/v1/proto.rs | 2 + backend/src/services/v1/purchases.rs | 439 + backend/src/services/v1/reviews.rs | 210 + backend/src/services/v1/stats.rs | 59 + backend/src/services/v1/uploads.rs | 151 + backend/src/services/v1/users.rs | 58 + backend/src/services/v1/wishlist.rs | 239 + backend/src/utils.rs | 39 + buf.gen.yaml | 12 + proto/v1/auth.proto | 4 - 44 files changed, 89116 insertions(+), 65 deletions(-) create mode 100644 .gitignore create mode 100644 app/web/mobile-server.js create mode 100644 backend/.gitignore create mode 100644 backend/Cargo.lock create mode 100644 backend/diesel.toml create mode 100644 backend/migrations/00000000000000_diesel_initial_setup/down.sql create mode 100644 backend/migrations/00000000000000_diesel_initial_setup/up.sql create mode 100644 backend/migrations/2026-09-25-000000-0000_initial_setup/down.sql create mode 100644 backend/migrations/2026-09-25-000000-0000_initial_setup/up.sql create mode 100644 backend/rust-toolchain.toml create mode 100644 backend/src/config.rs create mode 100644 backend/src/db.rs create mode 100644 backend/src/fapshi.rs create mode 100644 backend/src/jwt.rs create mode 100644 backend/src/middleware/auth.rs create mode 100644 backend/src/middleware/logging.rs create mode 100644 backend/src/middleware/mod.rs create mode 100644 backend/src/models.rs create mode 100644 backend/src/proto/buf/bookbridge.v1.rs create mode 100644 backend/src/proto/mod.rs create mode 100644 backend/src/proto/svc/bookbridge.v1.rs create mode 100644 backend/src/schema.rs create mode 100644 backend/src/services/mod.rs create mode 100644 backend/src/services/v1/auth.rs create mode 100644 backend/src/services/v1/books.rs create mode 100644 backend/src/services/v1/boosts.rs create mode 100644 backend/src/services/v1/chat.rs create mode 100644 backend/src/services/v1/helpers.rs create mode 100644 backend/src/services/v1/locations.rs create mode 100644 backend/src/services/v1/mod.rs create mode 100644 backend/src/services/v1/notifications.rs create mode 100644 backend/src/services/v1/proto.rs create mode 100644 backend/src/services/v1/purchases.rs create mode 100644 backend/src/services/v1/reviews.rs create mode 100644 backend/src/services/v1/stats.rs create mode 100644 backend/src/services/v1/uploads.rs create mode 100644 backend/src/services/v1/users.rs create mode 100644 backend/src/services/v1/wishlist.rs create mode 100644 backend/src/utils.rs create mode 100644 buf.gen.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c8d8363 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.ckb diff --git a/app/web/mobile-server.js b/app/web/mobile-server.js new file mode 100644 index 0000000..600930a --- /dev/null +++ b/app/web/mobile-server.js @@ -0,0 +1,80 @@ +#!/usr/bin/env bun +// Minimal dependency-free static file server for the BookBridge web build. + +import { extname, join, normalize, sep } from "node:path"; + +const ROOT = normalize(join(import.meta.dir, "curr")); +const HOSTNAME = process.env.HOST || "0.0.0.0"; +const PORT = Number(process.env.FRONTEND_PORT || 3004); + +const MIME = { + ".html": "text/html; charset=utf-8", + ".js": "text/javascript; charset=utf-8", + ".mjs": "text/javascript; charset=utf-8", + ".json": "application/json; charset=utf-8", + ".css": "text/css; charset=utf-8", + ".wasm": "application/wasm", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".svg": "image/svg+xml", + ".webp": "image/webp", + ".ico": "image/x-icon", + ".woff": "font/woff", + ".woff2": "font/woff2", + ".ttf": "font/ttf", + ".otf": "font/otf", + ".bin": "application/octet-stream", + ".map": "application/json; charset=utf-8", + ".txt": "text/plain; charset=utf-8", +}; + +function contentType(path) { + return MIME[extname(path).toLowerCase()] || "application/octet-stream"; +} + +function resolveSafe(pathname) { + const decoded = decodeURIComponent(pathname); + const rel = decoded.endsWith("/") ? `${decoded}index.html` : decoded; + const resolved = normalize(join(ROOT, rel)); + if (resolved !== ROOT && !resolved.startsWith(ROOT + sep)) { + return null; + } + return resolved; +} + +const INDEX = join(ROOT, "index.html"); + +Bun.serve({ + hostname: HOSTNAME, + port: PORT, + async fetch(req) { + if (req.method !== "GET" && req.method !== "HEAD") { + return new Response("Method Not Allowed", { status: 405 }); + } + + const { pathname } = new URL(req.url); + const filePath = resolveSafe(pathname); + if (filePath) { + const file = Bun.file(filePath); + if (await file.exists()) { + return new Response(file, { + headers: { "content-type": contentType(filePath) }, + }); + } + } + + const index = Bun.file(INDEX); + if (await index.exists()) { + return new Response(index, { + status: 200, + headers: { "content-type": "text/html; charset=utf-8" }, + }); + } + + return new Response("Not Found", { status: 404 }); + }, +}); + +console.log(`[app] serving ${ROOT} on http://${HOSTNAME}:${PORT}`); diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..be03c1f --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,7 @@ +.env +*.env +**/.env +**/.env.* +!**/.env.example +target +.weft diff --git a/backend/Cargo.lock b/backend/Cargo.lock new file mode 100644 index 0000000..0958619 --- /dev/null +++ b/backend/Cargo.lock @@ -0,0 +1,3078 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "const-random", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "backend" +version = "0.1.0" +dependencies = [ + "async-stream", + "axum", + "bigdecimal", + "buffa", + "buffa-types", + "chrono", + "connectrpc", + "diesel", + "diesel_migrations", + "dotenvy", + "h3o", + "http", + "jsonwebtoken", + "pq-sys", + "rand 0.10.3", + "reqwest", + "ring", + "serde", + "serde_json", + "sha2", + "thiserror", + "tokio", + "tower-http 0.7.1", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bigdecimal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "buffa" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92f2f5df67a9d5ccfc65237bfc954c56328aee40a04a9b92381ecba370be246" +dependencies = [ + "base64 0.22.1", + "bytes", + "foldhash", + "hashbrown 0.15.5", + "once_cell", + "rustversion", + "serde", + "serde_json", + "smoothutf8", + "thiserror", +] + +[[package]] +name = "buffa-types" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15b05c8418f1e200e406e5b19df97400dffa833e2450e4392c506896cbc97ac" +dependencies = [ + "buffa", + "bytes", + "jiff", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + +[[package]] +name = "cc" +version = "1.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "connectrpc" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457cfa540c62e1b0b05db676cc9a9129162ad94d3a3eec6f2d19706c53acae7d" +dependencies = [ + "async-trait", + "axum", + "base64 0.22.1", + "buffa", + "bytes", + "flate2", + "futures", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "libc", + "percent-encoding", + "pin-project", + "serde", + "serde_json", + "sync_wrapper", + "thiserror", + "tokio", + "tokio-util", + "tower", + "tower-http 0.6.11", + "tracing", + "wasm-bindgen-futures", + "zstd", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "diesel" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b934ddbdcb2abb9f9fc9c30bd47bcc5618b615eea1d334cda5fdf8ff9b072a" +dependencies = [ + "bigdecimal", + "bitflags 2.13.2", + "byteorder", + "chrono", + "diesel_derives", + "downcast-rs", + "itoa", + "num-bigint", + "num-integer", + "num-traits", + "pq-sys", + "r2d2", + "serde_json", + "uuid", +] + +[[package]] +name = "diesel_derives" +version = "2.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecbd51fb6c020672543641167efa4e6417ff7ad76849ed556ace3595e72de03a" +dependencies = [ + "diesel_table_macro_syntax", + "dsl_auto_type", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "diesel_migrations" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d0f4a98124ba6d4ca75da535f65984badec16a003b6e2f94a01e31a79490b8" +dependencies = [ + "diesel", + "migrations_internals", + "migrations_macros", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c" +dependencies = [ + "syn 2.0.119", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + +[[package]] +name = "dsl_auto_type" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd122633e4bef06db27737f21d3738fb89c8f6d5360d6d9d7635dda142a7757e" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "zlib-rs", +] + +[[package]] +name = "float_eq" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a80e3145d8ad11ba0995949bbcf48b9df2be62772b3d351ef017dff6ecb853" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h3o" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de3592e1f699692aa0525c42ff7879ec3ee7e36329af20967bc910a1cdc39c7" +dependencies = [ + "ahash", + "either", + "float_eq", + "h3o-bit", + "libm", +] + +[[package]] +name = "h3o-bit" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b42eb4efef1f96510ae1a33b2682562a677d504641e9903a77bf5c666b9013e" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" +dependencies = [ + "base64 0.23.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", +] + +[[package]] +name = "jiff-static" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "11.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75fe14a82d81e5f5af639997db37d8b96045938a7ac6ab18cdbe1c7467e05e1" +dependencies = [ + "base64 0.22.1", + "ed25519-dalek", + "getrandom 0.2.17", + "hmac", + "js-sys", + "p256", + "p384", + "pem", + "rand 0.8.8", + "rsa", + "serde", + "serde_json", + "sha2", + "signature", + "simple_asn1", + "zeroize", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "lru-slab" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f" + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "migrations_internals" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c791ecdf977c99f45f23280405d7723727470f6689a5e6dbf513ac547ae10d" +dependencies = [ + "serde", + "toml", +] + +[[package]] +name = "migrations_macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36fc5ac76be324cfd2d3f2cf0fdf5d5d3c4f14ed8aaebadb09e304ba42282703" +dependencies = [ + "migrations_internals", + "proc-macro2", + "quote", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.8", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "openssl-sys" +version = "0.9.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "pq-src" +version = "0.3.13+libpq-18.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70bbe4cdadd409f38beac5496e6b2d3f8a6a2881dc2705add79dfc9905b683c" +dependencies = [ + "cc", + "openssl-sys", +] + +[[package]] +name = "pq-sys" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9152654059e4fb5b66a4052acf3ee43a7a7132332e44cdb72a81ee93bd038950" +dependencies = [ + "libc", + "pkg-config", + "pq-src", + "vcpkg", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quinn" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc" +dependencies = [ + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.3", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http 0.6.11", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustls" +version = "0.23.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" + +[[package]] +name = "smoothutf8" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4ec95892483d6d94284caccfddb9b77111a4dcac33ed25d624248def0fa5f1" +dependencies = [ + "simdutf8", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "winnow 0.7.15", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.2", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "tracing", + "url", +] + +[[package]] +name = "tower-http" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a05a66a4fdd61cbbe0a1d755ffe0ca6aba159dd4820936a0ff8a8278245b9c" +dependencies = [ + "bitflags 2.13.2", + "bytes", + "http", + "percent-encoding", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef6dac1e96601b4fb3acccccff2139741fcb757cb9a36089bf5be91cfb285ce" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.6", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e8fafad82b542ff3717217ecdc736231b59e387768c9630123b4ce4d2db44" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595f56e044df4f46a0c9a626f65c3d99eb8488f7e8a8baa12dd76326d9710bf2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.0+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef0a8027ec3ee71300ab3bcbcd0393f434aa72b91ca6d635a39941deae8eea0" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 2927186..76448a4 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -4,3 +4,32 @@ version = "0.1.0" edition = "2024" [dependencies] +async-stream = "0.3" +axum = "0.8.9" +bigdecimal = { version = "0.4", features = ["serde"] } +buffa = { version = "0.9", features = ["json"] } +buffa-types = { version = "0.9", features = ["json"] } +chrono = { version = "0.4", features = ["serde"] } +connectrpc = { version = "0.9", features = ["axum", "server"] } +diesel = { version = "2.3.12", features = ["chrono", "numeric", "postgres", "r2d2", "serde_json", "uuid", "without-deprecated"] } +diesel_migrations = { version = "2.3", features = ["postgres"] } +dotenvy = "0.15.7" +h3o = "0.6" +http = "1.5.0" +jsonwebtoken = { version = "11", features = ["rust_crypto"] } +pq-sys = { version = "0.7", features = ["bundled"] } +rand = "0.10.2" +reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } +ring = "0.17" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sha2 = "0.10" +thiserror = "2.0.20" +tokio = { version = "1.53.1", features = ["full", "rt-multi-thread"] } +tower-http = { version = "0.7.1", features = ["cors"] } +tracing = "0.1.44" +tracing-subscriber = "0.3.23" +uuid = { version = "1", features = ["serde", "v4", "v7"] } + +[profile.dev] +debug = "line-tables-only" diff --git a/backend/diesel.toml b/backend/diesel.toml new file mode 100644 index 0000000..a0d61bf --- /dev/null +++ b/backend/diesel.toml @@ -0,0 +1,9 @@ +# For documentation on how to configure this file, +# see https://diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" +custom_type_derives = ["diesel::query_builder::QueryId", "Clone"] + +[migrations_directory] +dir = "migrations" diff --git a/backend/migrations/00000000000000_diesel_initial_setup/down.sql b/backend/migrations/00000000000000_diesel_initial_setup/down.sql new file mode 100644 index 0000000..8fb31a8 --- /dev/null +++ b/backend/migrations/00000000000000_diesel_initial_setup/down.sql @@ -0,0 +1,2 @@ +DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); +DROP FUNCTION IF EXISTS diesel_set_updated_at(); diff --git a/backend/migrations/00000000000000_diesel_initial_setup/up.sql b/backend/migrations/00000000000000_diesel_initial_setup/up.sql new file mode 100644 index 0000000..08d6f2a --- /dev/null +++ b/backend/migrations/00000000000000_diesel_initial_setup/up.sql @@ -0,0 +1,18 @@ +CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ +BEGIN + EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s + FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ +BEGIN + IF ( + NEW IS DISTINCT FROM OLD AND + NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at + ) THEN + NEW.updated_at := current_timestamp; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; diff --git a/backend/migrations/2026-09-25-000000-0000_initial_setup/down.sql b/backend/migrations/2026-09-25-000000-0000_initial_setup/down.sql new file mode 100644 index 0000000..7f1e764 --- /dev/null +++ b/backend/migrations/2026-09-25-000000-0000_initial_setup/down.sql @@ -0,0 +1,37 @@ +-- Drop tables in reverse order of foreign keys +drop table if exists book_purchases; +drop table if exists donations; +drop table if exists boosts; +drop table if exists reviews; +drop table if exists transactions; +drop table if exists payments; +drop table if exists payment_intents; +drop table if exists notifications; +drop table if exists notification_bodies; +drop table if exists notification_template_translations; +drop table if exists notification_templates; +drop table if exists wishlist_items; +drop table if exists conversation_messages; +drop table if exists conversations; +drop table if exists book_pictures; +drop table if exists books; +drop table if exists book_categories; +drop table if exists meetup_locations; +drop table if exists indexed_locations; +drop table if exists verification_documents; +drop table if exists user_sessions; +drop table if exists users; +drop table if exists uploads; + +-- Drop custom types +drop type if exists verification_document_type; +drop type if exists transaction_status; +drop type if exists payment_method; +drop type if exists payment_status; +drop type if exists payment_type; +drop type if exists book_status; +drop type if exists book_picture_type; +drop type if exists book_condition; +drop type if exists location_type; + +drop function if exists set_updated_at(); diff --git a/backend/migrations/2026-09-25-000000-0000_initial_setup/up.sql b/backend/migrations/2026-09-25-000000-0000_initial_setup/up.sql new file mode 100644 index 0000000..2b6298e --- /dev/null +++ b/backend/migrations/2026-09-25-000000-0000_initial_setup/up.sql @@ -0,0 +1,352 @@ +-- ============================================================================= +-- BookBridge — PostgreSQL Schema (Initial Setup) +-- ============================================================================= + +create or replace function set_updated_at() +returns trigger +language plpgsql +as $$ +begin + new.updated_at = now(); + return new; +end; +$$; + +create type location_type as enum ('book', 'meetup'); +create type book_condition as enum ('new', 'like_new', 'good', 'fair', 'poor'); +create type book_picture_type as enum ('front', 'back', 'other'); +create type book_status as enum ('available', 'sold', 'reserved', 'expired', 'removed'); +create type payment_type as enum ('book', 'donation', 'boost'); +create type payment_status as enum ('pending', 'completed', 'failed'); +create type payment_method as enum ('fapshi'); +create type transaction_status as enum ('held', 'released', 'refunded', 'disputed'); +create type verification_document_type as enum ('nationalid', 'schoolid'); + +-- ============================================================================= +-- uploads +-- ============================================================================= + +create table if not exists uploads ( + id uuid primary key default uuidv7(), + storage_key varchar(512) unique not null, + file_name varchar(255) not null, + content_type varchar(100) not null, + size_bytes bigint not null check (size_bytes > 0), + uploaded_by uuid, + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp +); + +create or replace trigger trg_uploads_updated_at + before update on uploads + for each row execute function set_updated_at(); + +-- ============================================================================= +-- users & auth +-- ============================================================================= + +create table if not exists users ( + id uuid primary key default uuidv7(), + email varchar(255), + phone varchar(255) not null unique, + password_hash varchar(255), + first_name varchar(32) not null, + last_name varchar(32) not null, + avatar_id uuid references uploads(id) on delete set null, + rating numeric(3,2) not null default 0.00 check (rating between 0 and 5), + verified boolean not null default false, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + deleted_at timestamptz +); + +alter table uploads add constraint fk_uploads_uploaded_by foreign key (uploaded_by) references users(id) on delete set null; + +create or replace trigger trg_users_updated_at + before update on users + for each row execute function set_updated_at(); + +create index if not exists idx_users_phone on users (phone); +create index if not exists idx_users_email on users (email); +create index if not exists idx_uploads_uploaded_by on uploads (uploaded_by); + +create table if not exists user_sessions ( + session_id uuid primary key default uuidv7(), + user_id uuid not null references users(id) on delete cascade, + refresh_token_hash bytea not null unique, + expires_at timestamptz not null, + rotated_at timestamptz not null default now(), + fcm_token text, + created_at timestamptz not null default now() +); + +create index if not exists idx_user_sessions_user_id on user_sessions (user_id); + +create table if not exists verification_documents ( + user_id uuid not null references users(id) on delete cascade, + upload_id uuid not null references uploads(id) on delete cascade, + document_type verification_document_type not null, + created_at timestamptz not null default now(), + primary key (user_id, upload_id) +); + +-- ============================================================================= +-- geo / indexed locations +-- ============================================================================= + +create table if not exists indexed_locations ( + id uuid primary key default uuidv7(), + type location_type not null, + latitude double precision not null, + longitude double precision not null, + h3_3 bigint not null, + h3_4 bigint not null, + h3_5 bigint not null, + h3_6 bigint not null, + h3_7 bigint not null +); + +create index if not exists idx_indexed_locations_h3_3 on indexed_locations (h3_3); +create index if not exists idx_indexed_locations_h3_4 on indexed_locations (h3_4); +create index if not exists idx_indexed_locations_h3_5 on indexed_locations (h3_5); +create index if not exists idx_indexed_locations_h3_6 on indexed_locations (h3_6); +create index if not exists idx_indexed_locations_h3_7 on indexed_locations (h3_7); + +create table if not exists meetup_locations ( + id uuid primary key default uuidv7(), + name text not null, + description text, + location_id uuid not null references indexed_locations(id) on delete cascade, + verified boolean not null default false, + created_at timestamptz not null default now() +); + +create index if not exists idx_meetup_locations_location_id on meetup_locations (location_id); + +-- ============================================================================= +-- books +-- ============================================================================= + +create table if not exists book_categories ( + id bigserial primary key, + name varchar(63) not null unique +); + +create table if not exists books ( + id uuid primary key default uuidv7(), + seller_id uuid not null references users(id) on delete cascade, + ebook_id uuid references uploads(id) on delete set null, + title varchar(255) not null, + author varchar(255) not null, + price integer not null check (price >= 0), + condition book_condition not null, + description text, + status book_status not null default 'available', + category bigint not null references book_categories(id) on delete cascade, + refundable boolean not null default false, + swapable boolean not null default false, + boost_expires_at timestamptz not null default now(), + expires_at timestamptz not null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + deleted_at timestamptz, + location uuid references indexed_locations(id) on delete set null +); + +create or replace trigger trg_books_updated_at + before update on books + for each row execute function set_updated_at(); + +create index if not exists idx_books_seller_id on books (seller_id); +create index if not exists idx_books_status on books (status); +create index if not exists idx_books_category on books (category); +create index if not exists idx_books_location on books (location); + +create table if not exists book_pictures ( + book_id uuid not null references books(id) on delete cascade, + upload_id uuid not null references uploads(id) on delete cascade, + type book_picture_type not null default 'other', + primary key (book_id, upload_id) +); + +create index if not exists idx_book_pictures_upload_id on book_pictures (upload_id); + +-- ============================================================================= +-- messaging +-- ============================================================================= + +create table if not exists conversations ( + id uuid primary key default uuidv7(), + book_id uuid not null references books(id) on delete cascade, + user_id uuid not null references users(id) on delete cascade, + created_at timestamptz not null default now(), + deleted_at timestamptz +); + +create index if not exists idx_conversations_book_id on conversations (book_id); +create index if not exists idx_conversations_user_id on conversations (user_id); + +create table if not exists conversation_messages ( + id uuid primary key default uuidv7(), + user_id uuid not null references users(id) on delete cascade, + conversation_id uuid not null references conversations(id) on delete cascade, + content text not null, + attachment uuid references uploads(id) on delete set null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + deleted_at timestamptz +); + +create or replace trigger trg_conversation_messages_updated_at + before update on conversation_messages + for each row execute function set_updated_at(); + +create index if not exists idx_conversation_messages_conversation_id + on conversation_messages (conversation_id, created_at); +create index if not exists idx_conversation_messages_user_id on conversation_messages (user_id); + +-- ============================================================================= +-- wishlist +-- ============================================================================= + +create table if not exists wishlist_items ( + user_id uuid not null references users(id) on delete cascade, + book_id uuid not null references books(id) on delete cascade, + created_at timestamptz not null default now(), + primary key (user_id, book_id) +); + +create index if not exists idx_wishlist_items_book_id on wishlist_items (book_id); + +-- ============================================================================= +-- notifications +-- ============================================================================= + +create table if not exists notification_templates ( + id uuid primary key, + parameters jsonb not null default '{}' +); + +create table if not exists notification_template_translations ( + template_id uuid not null references notification_templates(id) on delete cascade, + lang varchar(2) not null, + format text not null, + primary key (template_id, lang) +); + +create table if not exists notification_bodies ( + id uuid primary key default uuidv7(), + template_id uuid not null references notification_templates(id) on delete cascade, + template_arguments jsonb not null default '{}' +); + +create index if not exists idx_notification_bodies_template_id on notification_bodies (template_id); + +create table if not exists notifications ( + id uuid primary key default uuidv7(), + user_id uuid references users(id) on delete cascade, + body_id uuid references notification_bodies(id) on delete cascade, + template_arguments jsonb not null default '{}', + read_at timestamptz, + created_at timestamptz not null default now() +); + +create index if not exists idx_notifications_user_id on notifications (user_id, created_at desc); + +-- ============================================================================= +-- reviews +-- ============================================================================= + +create table if not exists reviews ( + id uuid primary key default uuidv7(), + author_id uuid not null references users(id) on delete cascade, + reviewee_id uuid references users(id) on delete cascade, + transaction_id uuid, + rating numeric(3,2) not null check (rating between 1 and 5), + content text, + created_at timestamptz not null default now() +); + +create index if not exists idx_reviews_author_id on reviews (author_id); +create index if not exists idx_reviews_reviewee_id on reviews (reviewee_id); + +-- ============================================================================= +-- payments and transactions +-- ============================================================================= + +create table if not exists payment_intents ( + id uuid primary key default uuidv7(), + user_id uuid not null references users(id) on delete cascade, + method payment_method not null, + amount integer not null check (amount > 0), + status payment_status not null default 'pending', + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +create or replace trigger trg_payment_intents_updated_at + before update on payment_intents + for each row execute function set_updated_at(); + +create index if not exists idx_payment_intents_user_id on payment_intents (user_id); + +create table if not exists payments ( + intent_id uuid primary key references payment_intents(id) on delete cascade, + platform_transaction_reference text not null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +create or replace trigger trg_payments_updated_at + before update on payments + for each row execute function set_updated_at(); + +create table if not exists transactions ( + payment_id uuid primary key references payments(intent_id) on delete cascade, + recipient uuid not null references users(id) on delete cascade, + transaction_status transaction_status not null default 'held', + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + refunded_at timestamptz, + deleted_at timestamptz +); + +create or replace trigger trg_transactions_updated_at + before update on transactions + for each row execute function set_updated_at(); + +create index if not exists idx_transactions_recipient on transactions (recipient); + +alter table reviews add constraint fk_reviews_transaction foreign key (transaction_id) references transactions(payment_id) on delete set null; + +-- ============================================================================= +-- payment types +-- ============================================================================= + +create table if not exists boosts ( + payment_id uuid primary key references payments(intent_id) on delete cascade, + book_id uuid not null references books(id) on delete cascade, + created_at timestamptz not null default now(), + expires_at timestamptz not null +); + +create index if not exists idx_boosts_book_id on boosts (book_id); + +create table if not exists donations ( + payment_id uuid primary key references payments(intent_id) on delete cascade, + user_id uuid references users(id) on delete set null, + message text, + created_at timestamptz not null default now() +); + +create index if not exists idx_donations_user_id on donations (user_id); + +create table if not exists book_purchases ( + transaction_id uuid primary key references transactions(payment_id) on delete cascade, + book_id uuid not null references books(id) on delete cascade, + meetup_location uuid references meetup_locations(id) on delete set null, + confirmed boolean not null default false, + created_at timestamptz not null default now() +); + +create index if not exists idx_book_purchases_book_id on book_purchases (book_id); diff --git a/backend/rust-toolchain.toml b/backend/rust-toolchain.toml new file mode 100644 index 0000000..292fe49 --- /dev/null +++ b/backend/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/backend/schema.sql b/backend/schema.sql index 85134c5..5f758c1 100644 --- a/backend/schema.sql +++ b/backend/schema.sql @@ -1,3 +1,7 @@ +-- ============================================================================= +-- BookBridge — PostgreSQL Schema +-- ============================================================================= + create or replace function set_updated_at() returns trigger language plpgsql @@ -8,7 +12,6 @@ begin end; $$; - create type location_type as enum ('book', 'meetup'); create type book_condition as enum ('new', 'like_new', 'good', 'fair', 'poor'); create type book_picture_type as enum ('front', 'back', 'other'); @@ -19,12 +22,34 @@ create type payment_method as enum ('fapshi'); create type transaction_status as enum ('held', 'released', 'refunded', 'disputed'); create type verification_document_type as enum ('nationalid', 'schoolid'); +-- ============================================================================= +-- uploads +-- ============================================================================= + +create table if not exists uploads ( + id uuid primary key default uuidv7(), + storage_key varchar(512) unique not null, + file_name varchar(255) not null, + content_type varchar(100) not null, + size_bytes bigint not null check (size_bytes > 0), + uploaded_by uuid, + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp +); + +create or replace trigger trg_uploads_updated_at + before update on uploads + for each row execute function set_updated_at(); + +-- ============================================================================= +-- users & auth +-- ============================================================================= --- TODO: Add user kyc verification, method to set notified device create table if not exists users ( id uuid primary key default uuidv7(), email varchar(255), - phone varchar(255) not null, + phone varchar(255) not null unique, + password_hash varchar(255), first_name varchar(32) not null, last_name varchar(32) not null, avatar_id uuid references uploads(id) on delete set null, @@ -35,16 +60,22 @@ create table if not exists users ( deleted_at timestamptz ); +alter table uploads add constraint fk_uploads_uploaded_by foreign key (uploaded_by) references users(id) on delete set null; + create or replace trigger trg_users_updated_at before update on users for each row execute function set_updated_at(); +create index if not exists idx_users_phone on users (phone); +create index if not exists idx_users_email on users (email); +create index if not exists idx_uploads_uploaded_by on uploads (uploaded_by); + create table if not exists user_sessions ( session_id uuid primary key default uuidv7(), user_id uuid not null references users(id) on delete cascade, - refresh_token_hash bytea not null unique, -- sha256 of the opaque refresh token; never store the raw token - expires_at timestamptz not null, -- refresh token expiry - rotated_at timestamptz not null default now(), -- set on every token rotation + refresh_token_hash bytea not null unique, + expires_at timestamptz not null, + rotated_at timestamptz not null default now(), fcm_token text, created_at timestamptz not null default now() ); @@ -52,50 +83,27 @@ create table if not exists user_sessions ( create index if not exists idx_user_sessions_user_id on user_sessions (user_id); create table if not exists verification_documents ( - user_id uuid not null references users(id) on delete cascade, - upload_id uuid not null references uploads(id) on delete cascade, + user_id uuid not null references users(id) on delete cascade, + upload_id uuid not null references uploads(id) on delete cascade, document_type verification_document_type not null, - created_at timestamptz not null default now() -); - - --- ============================================================================= --- uploads --- ============================================================================= - -create table if not exists uploads ( - id uuid primary key default uuidv7(), - storage_key varchar(512) unique not null, - file_name varchar(255) not null, - content_type varchar(100) not null, - size_bytes bigint not null check (size_bytes > 0), - uploaded_by uuid references users(id) on delete set null, - created_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default now(), + primary key (user_id, upload_id) ); -create or replace trigger trg_uploads_updated_at - before update on uploads - for each row execute function set_updated_at(); - -create index if not exists idx_uploads_uploaded_by on uploads (uploaded_by); - - -- ============================================================================= -- geo / indexed locations -- ============================================================================= --- too much yes create table if not exists indexed_locations ( id uuid primary key default uuidv7(), type location_type not null, latitude double precision not null, longitude double precision not null, - h3_3 bigint not null, -- 274.08km long diameter - h3_4 bigint not null, -- 39.16km long diameter - h3_5 bigint not null, -- 14.79km long diameter - h3_6 bigint not null, -- 05.60km long diameter - h3_7 bigint not null, -- 02.11km long diameter + h3_3 bigint not null, + h3_4 bigint not null, + h3_5 bigint not null, + h3_6 bigint not null, + h3_7 bigint not null ); create index if not exists idx_indexed_locations_h3_3 on indexed_locations (h3_3); @@ -115,7 +123,6 @@ create table if not exists meetup_locations ( create index if not exists idx_meetup_locations_location_id on meetup_locations (location_id); - -- ============================================================================= -- books -- ============================================================================= @@ -123,16 +130,15 @@ create index if not exists idx_meetup_locations_location_id on meetup_locations create table if not exists book_categories ( id bigserial primary key, name varchar(63) not null unique - name text ); create table if not exists books ( id uuid primary key default uuidv7(), seller_id uuid not null references users(id) on delete cascade, - ebook_id uuid not null references uploads(id) on delete set null, + ebook_id uuid references uploads(id) on delete set null, title varchar(255) not null, author varchar(255) not null, - price integer not null check (price > 0), + price integer not null check (price >= 0), condition book_condition not null, description text, status book_status not null default 'available', @@ -144,7 +150,7 @@ create table if not exists books ( created_at timestamptz not null default now(), updated_at timestamptz not null default now(), deleted_at timestamptz, - location uuid references indexed_locations(id) on delete cascade + location uuid references indexed_locations(id) on delete set null ); create or replace trigger trg_books_updated_at @@ -157,16 +163,14 @@ create index if not exists idx_books_category on books (category); create index if not exists idx_books_location on books (location); create table if not exists book_pictures ( - upload_id uuid not null references uploads(id) on delete cascade, book_id uuid not null references books(id) on delete cascade, - primary key (book_id, upload_id) - + upload_id uuid not null references uploads(id) on delete cascade, type book_picture_type not null default 'other', + primary key (book_id, upload_id) ); create index if not exists idx_book_pictures_upload_id on book_pictures (upload_id); - -- ============================================================================= -- messaging -- ============================================================================= @@ -201,7 +205,6 @@ create index if not exists idx_conversation_messages_conversation_id on conversation_messages (conversation_id, created_at); create index if not exists idx_conversation_messages_user_id on conversation_messages (user_id); - -- ============================================================================= -- wishlist -- ============================================================================= @@ -215,7 +218,6 @@ create table if not exists wishlist_items ( create index if not exists idx_wishlist_items_book_id on wishlist_items (book_id); - -- ============================================================================= -- notifications -- ============================================================================= @@ -252,20 +254,21 @@ create table if not exists notifications ( create index if not exists idx_notifications_user_id on notifications (user_id, created_at desc); -- ============================================================================= --- feedback +-- reviews -- ============================================================================= create table if not exists reviews ( - id uuid primary key default uuidv7(), - author_id uuid not null references users(id) on delete cascade, - rating numeric(3,2) check (rating between 1 and 5), - content text, - created_at timestamptz not null default now() + id uuid primary key default uuidv7(), + author_id uuid not null references users(id) on delete cascade, + reviewee_id uuid references users(id) on delete cascade, + transaction_id uuid, + rating numeric(3,2) not null check (rating between 1 and 5), + content text, + created_at timestamptz not null default now() ); --- todo author-reviews, book-reviews(maybe), others create index if not exists idx_reviews_author_id on reviews (author_id); - +create index if not exists idx_reviews_reviewee_id on reviews (reviewee_id); -- ============================================================================= -- payments and transactions @@ -275,7 +278,7 @@ create table if not exists payment_intents ( id uuid primary key default uuidv7(), user_id uuid not null references users(id) on delete cascade, method payment_method not null, - amount integer not null, + amount integer not null check (amount > 0), status payment_status not null default 'pending', created_at timestamptz not null default now(), updated_at timestamptz not null default now() @@ -288,7 +291,7 @@ create or replace trigger trg_payment_intents_updated_at create index if not exists idx_payment_intents_user_id on payment_intents (user_id); create table if not exists payments ( - intent_id uuid primary key references payment_intents(id), + intent_id uuid primary key references payment_intents(id) on delete cascade, platform_transaction_reference text not null, created_at timestamptz not null default now(), updated_at timestamptz not null default now() @@ -314,6 +317,7 @@ create or replace trigger trg_transactions_updated_at create index if not exists idx_transactions_recipient on transactions (recipient); +alter table reviews add constraint fk_reviews_transaction foreign key (transaction_id) references transactions(payment_id) on delete set null; -- ============================================================================= -- payment types diff --git a/backend/src/config.rs b/backend/src/config.rs new file mode 100644 index 0000000..46c2112 --- /dev/null +++ b/backend/src/config.rs @@ -0,0 +1,86 @@ +use dotenvy::dotenv; +use std::env; +use std::fmt; + +/// Application configuration loaded from environment variables. +#[derive(Clone)] +pub struct Config { + pub database_url: String, + pub jwt_secret: String, + pub port: u16, + pub fapshi_api_user: Option, + pub fapshi_api_key: Option, + pub fapshi_base_url: String, + pub fapshi_sandbox: bool, + pub firebase_project_id: Option, + pub firebase_service_account_path: Option, + pub fcm_server_key: Option, + pub cors_allowed_origins: Vec, +} + +impl fmt::Debug for Config { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Config") + .field("database_url", &"[redacted]") + .field("jwt_secret", &"[redacted]") + .field("port", &self.port) + .field("fapshi_api_user", &self.fapshi_api_user.as_ref().map(|_| "[redacted]")) + .field("fapshi_api_key", &self.fapshi_api_key.as_ref().map(|_| "[redacted]")) + .field("fapshi_base_url", &self.fapshi_base_url) + .field("fapshi_sandbox", &self.fapshi_sandbox) + .field("firebase_project_id", &self.firebase_project_id) + .field("cors_allowed_origins", &self.cors_allowed_origins) + .finish() + } +} + +impl Config { + pub fn load() -> Result> { + let _ = dotenv(); + tracing::debug!("Loading application environment configuration"); + + let database_url = env::var("DATABASE_URL") + .unwrap_or_else(|_| "postgresql://postgres:postgres@localhost:5432/bookbridge".to_string()); + let jwt_secret = env::var("JWT_SECRET") + .unwrap_or_else(|_| "development_jwt_secret_must_change_in_production_32bytes".to_string()); + let port: u16 = env::var("PORT") + .unwrap_or_else(|_| "3040".to_string()) + .parse() + .unwrap_or(3040); + + let fapshi_api_user = env::var("FAPSHI_API_USER").ok(); + let fapshi_api_key = env::var("FAPSHI_API_KEY").ok(); + let fapshi_base_url = env::var("FAPSHI_BASE_URL") + .unwrap_or_else(|_| "https://api.fapshi.com".to_string()); + let fapshi_sandbox = env::var("FAPSHI_SANDBOX") + .map(|v| v == "true" || v == "1") + .unwrap_or(false); + + let firebase_project_id = env::var("FIREBASE_PROJECT_ID").ok(); + let firebase_service_account_path = env::var("FIREBASE_SERVICE_ACCOUNT_PATH").ok(); + let fcm_server_key = env::var("FCM_SERVER_KEY").ok(); + + let cors_allowed_origins = env::var("CORS_ALLOWED_ORIGINS") + .map(|v| { + v.split(',') + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .collect() + }) + .unwrap_or_default(); + + Ok(Self { + database_url, + jwt_secret, + port, + fapshi_api_user, + fapshi_api_key, + fapshi_base_url, + fapshi_sandbox, + firebase_project_id, + firebase_service_account_path, + fcm_server_key, + cors_allowed_origins, + }) + } +} diff --git a/backend/src/db.rs b/backend/src/db.rs new file mode 100644 index 0000000..8fa1a44 --- /dev/null +++ b/backend/src/db.rs @@ -0,0 +1,62 @@ +use crate::config::Config; +use diesel::pg::PgConnection; +use diesel::r2d2::{ConnectionManager, Pool, PoolError, PooledConnection}; +use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; +use std::time::Duration; + +pub type PgPool = Pool>; +pub type PgPooledConnection = PooledConnection>; + +pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); + +const CONNECT_TIMEOUT_SECS: u32 = 10; + +pub struct Database { + pool: PgPool, +} + +impl Database { + pub fn connect(conf: &Config) -> Result> { + tracing::debug!("Initializing PostgreSQL connection pool"); + let url = with_connect_timeout(&conf.database_url); + let manager = ConnectionManager::::new(url); + let pool = Pool::builder() + .max_size(20) + .min_idle(Some(2)) + .connection_timeout(Duration::from_secs(CONNECT_TIMEOUT_SECS as u64)) + .build(manager) + .map_err(|err| { + tracing::error!(%err, "Failed to initialize database connection pool"); + err + })?; + + tracing::info!("PostgreSQL connection pool successfully initialized"); + Ok(Self { pool }) + } + + pub fn get_conn(&self) -> Result { + tracing::trace!("Acquiring database connection from pool"); + self.pool.get().map_err(|err| { + tracing::error!(%err, "Failed to checkout database connection from pool"); + err + }) + } +} + +pub fn run_migrations(database_url: &str) -> Result<(), Box> { + use diesel::Connection; + let url = with_connect_timeout(database_url); + let mut connection = PgConnection::establish(&url)?; + connection + .run_pending_migrations(MIGRATIONS) + .map_err(|err| format!("failed to run embedded migrations: {err}"))?; + Ok(()) +} + +fn with_connect_timeout(database_url: &str) -> String { + if database_url.contains("connect_timeout") { + return database_url.to_string(); + } + let separator = if database_url.contains('?') { '&' } else { '?' }; + format!("{database_url}{separator}connect_timeout={CONNECT_TIMEOUT_SECS}") +} diff --git a/backend/src/fapshi.rs b/backend/src/fapshi.rs new file mode 100644 index 0000000..d83a424 --- /dev/null +++ b/backend/src/fapshi.rs @@ -0,0 +1,191 @@ +use crate::config::Config; +use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE}; +use std::time::Duration; +use tracing::error; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub enum FapshiStatus { + Created, + Pending, + Successful, + Failed, + Expired, + #[serde(other)] + Unknown, +} + +#[derive(Debug, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DirectPayRequest<'a> { + pub amount: u64, + pub phone: &'a str, + #[serde(skip_serializing_if = "Option::is_none")] + pub network: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + pub email: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + pub user_id: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + pub trans_id: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + pub reason: Option<&'a str>, +} + +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DirectPayResponse { + pub message: Option, + #[serde(alias = "transId", alias = "trans_id")] + pub trans_id: Option, + pub status: Option, + #[serde( + alias = "financialTransId", + alias = "financial_trans_id", + alias = "financialTransactionId" + )] + pub financial_trans_id: Option, +} + +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PaymentStatusResponse { + #[serde(alias = "transId", alias = "trans_id")] + pub trans_id: Option, + pub status: FapshiStatus, + pub amount: Option, + pub revenue: Option, + pub payer_name: Option, + pub email: Option, + pub redirect_url: Option, + pub external_id: Option, + pub user_id: Option, + pub message: Option, +} + +#[derive(Debug, Clone)] +pub struct Fapshi { + client: reqwest::Client, + base_url: String, + api_user: String, + api_key: String, + pub sandbox: bool, +} + +#[connectrpc::async_trait] +pub trait PaymentGateway: Send + Sync { + async fn direct_pay<'a>( + &self, + payload: &DirectPayRequest<'a>, + ) -> Result; + + async fn get_payment_status( + &self, + fapshi_trans_id: &str, + ) -> Result; +} + +#[connectrpc::async_trait] +impl PaymentGateway for Fapshi { + async fn direct_pay<'a>( + &self, + payload: &DirectPayRequest<'a>, + ) -> Result { + Fapshi::direct_pay(self, payload).await + } + + async fn get_payment_status( + &self, + fapshi_trans_id: &str, + ) -> Result { + Fapshi::get_payment_status(self, fapshi_trans_id).await + } +} + +impl Fapshi { + pub fn new(config: &Config) -> Self { + let base_url = if config.fapshi_sandbox { + "https://sandbox.fapshi.com".to_string() + } else { + config.fapshi_base_url.clone() + }; + + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(30)) + .build() + .expect("Failed to build reqwest Client for Fapshi"); + + Self { + client, + base_url, + api_user: config.fapshi_api_user.clone().unwrap_or_default(), + api_key: config.fapshi_api_key.clone().unwrap_or_default(), + sandbox: config.fapshi_sandbox, + } + } + + fn auth_headers(&self) -> HeaderMap { + let mut headers = HeaderMap::new(); + if let Ok(val) = HeaderValue::from_str(&self.api_user) { + headers.insert("apiuser", val); + } + if let Ok(val) = HeaderValue::from_str(&self.api_key) { + headers.insert("apikey", val); + } + headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); + headers + } + + pub async fn direct_pay<'a>( + &self, + payload: &DirectPayRequest<'a>, + ) -> Result { + let url = format!("{}/direct-pay", self.base_url); + let resp = self + .client + .post(&url) + .headers(self.auth_headers()) + .json(payload) + .send() + .await + .map_err(|e| format!("Failed to send direct-pay request: {e}"))?; + + if !resp.status().is_success() { + let status = resp.status(); + let body = resp.text().await.unwrap_or_default(); + error!(%status, %body, "Fapshi direct-pay failed"); + return Err(format!("Fapshi returned error {status}: {body}")); + } + + resp.json::() + .await + .map_err(|e| format!("Failed to parse direct-pay response: {e}")) + } + + pub async fn get_payment_status( + &self, + trans_id: &str, + ) -> Result { + let url = format!("{}/payment-status/{}", self.base_url, trans_id); + let resp = self + .client + .get(&url) + .headers(self.auth_headers()) + .send() + .await + .map_err(|e| format!("Failed to fetch payment status: {e}"))?; + + if !resp.status().is_success() { + let status = resp.status(); + let body = resp.text().await.unwrap_or_default(); + error!(%status, %body, "Fapshi payment-status check failed"); + return Err(format!("Fapshi payment-status failed {status}: {body}")); + } + + resp.json::() + .await + .map_err(|e| format!("Failed to parse payment-status response: {e}")) + } +} diff --git a/backend/src/jwt.rs b/backend/src/jwt.rs new file mode 100644 index 0000000..9cf5983 --- /dev/null +++ b/backend/src/jwt.rs @@ -0,0 +1,85 @@ +use jsonwebtoken as jwt; +use serde::{Deserialize, Serialize}; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use thiserror::Error; +use uuid::Uuid; + +pub const DEFAULT_ACCESS_TOKEN_TTL: Duration = Duration::from_secs(60 * 60 * 24); // 24 hours +pub const DEFAULT_REFRESH_TOKEN_TTL: Duration = Duration::from_secs(60 * 60 * 24 * 30); // 30 days + +#[derive(Debug, Error)] +pub enum JwtError { + #[error("JWT error: {0}")] + Token(#[from] jwt::errors::Error), + #[error("System clock error generating timestamp")] + InvalidTimestamp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct Claims { + pub sub: String, + pub user_id: Uuid, + pub session_id: Uuid, + pub exp: u64, + pub iat: u64, +} + +impl Claims { + pub fn new(user_id: Uuid, session_id: Uuid, ttl: Duration) -> Result { + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|_| JwtError::InvalidTimestamp)? + .as_secs(); + + let exp = now + ttl.as_secs(); + + Ok(Self { + sub: user_id.to_string(), + user_id, + session_id, + exp, + iat: now, + }) + } +} + +#[derive(Debug, Clone)] +pub struct JWT { + secret: Vec, +} + +impl JWT { + pub fn new(secret: impl AsRef<[u8]>) -> Self { + Self { + secret: secret.as_ref().to_vec(), + } + } + + pub fn encode(&self, claims: &Claims) -> Result { + tracing::trace!(%claims.user_id, "Encoding JWT token"); + let token = jwt::encode( + &jwt::Header::default(), + claims, + &jwt::EncodingKey::from_secret(&self.secret), + )?; + Ok(token) + } + + pub fn decode(&self, token: &str) -> Result { + tracing::trace!("Decoding and validating JWT token"); + match jwt::decode::( + token, + &jwt::DecodingKey::from_secret(&self.secret), + &jwt::Validation::default(), + ) { + Ok(data) => { + tracing::debug!(user_id = %data.claims.user_id, "JWT token successfully validated"); + Ok(data.claims) + } + Err(err) => { + tracing::warn!(%err, "JWT validation failed"); + Err(JwtError::Token(err)) + } + } + } +} diff --git a/backend/src/main.rs b/backend/src/main.rs index e7a11a9..d139d1c 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,3 +1,77 @@ -fn main() { - println!("Hello, world!"); +#![allow(refining_impl_trait_internal, refining_impl_trait_reachable)] + +use connectrpc::{ConnectRpcService, Router}; +use http::{Method, header}; +use std::net::SocketAddr; +use std::sync::Arc; +use std::time::Duration; +use tower_http::cors::CorsLayer; + +mod config; +mod db; +mod fapshi; +mod jwt; +mod middleware; +mod models; +mod proto; +mod schema; +mod services; +mod utils; + +#[tokio::main] +async fn main() -> Result<(), Box> { + tracing_subscriber::fmt::init(); + + let config = Arc::new(config::Config::load()?); + + // Allow migrations to be executed via `backend migrate` without starting the server + if std::env::args().nth(1).as_deref() == Some("migrate") { + tracing::info!("Running database migrations..."); + db::run_migrations(&config.database_url)?; + tracing::info!("Database migrations executed successfully. Exiting."); + return Ok(()); + } + + let db = Arc::new(db::Database::connect(&config)?); + let jwt = Arc::new(jwt::JWT::new(&config.jwt_secret)); + let fapshi = Arc::new(fapshi::Fapshi::new(&config)); + + let mut router = Router::new(); + router = services::v1::include(router, db.clone(), jwt.clone(), fapshi.clone()); + + let cors = CorsLayer::new() + .allow_origin(tower_http::cors::Any) + .allow_methods([Method::GET, Method::POST, Method::OPTIONS]) + .allow_headers([ + header::AUTHORIZATION, + header::CONTENT_TYPE, + header::ACCEPT, + header::HeaderName::from_static("connect-protocol-version"), + header::HeaderName::from_static("connect-timeout-ms"), + header::HeaderName::from_static("x-user-agent"), + header::HeaderName::from_static("x-grpc-web"), + ]) + .expose_headers([ + header::HeaderName::from_static("connect-protocol-version"), + header::HeaderName::from_static("grpc-status"), + header::HeaderName::from_static("grpc-message"), + header::HeaderName::from_static("grpc-status-details-bin"), + ]) + .max_age(Duration::from_secs(3600)); + + let connect_service = ConnectRpcService::new(router) + .with_interceptor(middleware::LoggingInterceptor::new()) + .with_interceptor(middleware::AuthInterceptor::new(&config.jwt_secret)); + + let app = axum::Router::new() + .fallback_service(connect_service) + .layer(cors); + + let addr: SocketAddr = format!("0.0.0.0:{}", config.port).parse()?; + tracing::info!("Starting BookBridge ConnectRPC server on {}", addr); + + let listener = tokio::net::TcpListener::bind(addr).await?; + axum::serve(listener, app).await?; + + Ok(()) } diff --git a/backend/src/middleware/auth.rs b/backend/src/middleware/auth.rs new file mode 100644 index 0000000..12e42cd --- /dev/null +++ b/backend/src/middleware/auth.rs @@ -0,0 +1,139 @@ +use crate::jwt::{Claims, JWT}; +use connectrpc::async_trait; +use connectrpc::error::ConnectError; +use connectrpc::interceptor::{ + Interceptor, Next, NextStream, PayloadStream, StreamRequest, StreamResponse, UnaryRequest, + UnaryResponse, +}; +use connectrpc::response::RequestContext; +use std::sync::Arc; +use uuid::Uuid; + +pub trait AuthContextExt { + fn claims(&self) -> Option<&Claims>; + + fn require_claims(&self) -> Result<&Claims, ConnectError>; + + fn user_id(&self) -> Result { + self.require_claims().map(|c| c.user_id) + } + + fn session_id(&self) -> Result { + self.require_claims().map(|c| c.session_id) + } +} + +impl AuthContextExt for RequestContext { + fn claims(&self) -> Option<&Claims> { + self.extensions().get::() + } + + fn require_claims(&self) -> Result<&Claims, ConnectError> { + self.claims().ok_or_else(|| { + ConnectError::unauthenticated("missing authenticated user credentials") + }) + } +} + +#[derive(Clone)] +pub struct AuthInterceptor { + jwt: Arc, +} + +impl AuthInterceptor { + pub fn new(secret: impl AsRef<[u8]>) -> Self { + Self { + jwt: Arc::new(JWT::new(secret)), + } + } + + fn is_public_path(path: &str) -> bool { + let normalized = path.trim_start_matches('/'); + matches!( + normalized, + "bookbridge.v1.AuthService/SignUp" + | "bookbridge.v1.AuthService/SignIn" + | "bookbridge.v1.AuthService/SignInWithGoogle" + | "bookbridge.v1.AuthService/RefreshSession" + | "bookbridge.v1.BookService/ListCategories" + | "bookbridge.v1.BookService/ListBooks" + | "bookbridge.v1.BookService/SearchBooks" + | "bookbridge.v1.BookService/GetBook" + | "bookbridge.v1.BookService/ListBooksBySeller" + | "bookbridge.v1.MeetupLocationService/ListMeetupLocations" + | "bookbridge.v1.StatsService/GetPlatformStats" + | "bookbridge.v1.UserService/GetUser" + | "bookbridge.v1.ReviewService/ListReviews" + ) + } + + fn authenticate(&self, ctx: &mut RequestContext) -> Result<(), ConnectError> { + let path = ctx.path().unwrap_or(""); + + if Self::is_public_path(path) { + if let Some(token) = extract_token(ctx) { + if let Ok(claims) = self.jwt.decode(&token) { + ctx.extensions_mut().insert(claims); + } + } + return Ok(()); + } + + let token = extract_token(ctx).ok_or_else(|| { + ConnectError::unauthenticated("missing authorization token in request headers") + })?; + + let claims = self.jwt.decode(&token).map_err(|err| { + tracing::warn!(%err, "Rejected request with invalid authorization token"); + ConnectError::unauthenticated("invalid or expired authorization token") + })?; + + ctx.extensions_mut().insert(claims); + Ok(()) + } +} + +fn extract_token(ctx: &RequestContext) -> Option { + if let Some(auth_val) = ctx.header("authorization") { + if let Ok(auth_str) = auth_val.to_str() { + if let Some(token) = auth_str.strip_prefix("Bearer ") { + return Some(token.trim().to_string()); + } + if !auth_str.trim().is_empty() { + return Some(auth_str.trim().to_string()); + } + } + } + + if let Some(jwt_val) = ctx.header("jwt") { + if let Ok(jwt_str) = jwt_val.to_str() { + if !jwt_str.trim().is_empty() { + return Some(jwt_str.trim().to_string()); + } + } + } + + None +} + +#[async_trait] +impl Interceptor for AuthInterceptor { + async fn intercept_unary( + &self, + mut req: UnaryRequest, + next: Next<'_>, + ) -> Result { + self.authenticate(&mut req.ctx)?; + next.run(req).await + } + + async fn intercept_streaming( + &self, + mut req: StreamRequest, + inbound: PayloadStream, + next: NextStream<'_>, + ) -> Result { + self.authenticate(&mut req.ctx)?; + next.run(req, inbound).await + } +} diff --git a/backend/src/middleware/logging.rs b/backend/src/middleware/logging.rs new file mode 100644 index 0000000..ec72590 --- /dev/null +++ b/backend/src/middleware/logging.rs @@ -0,0 +1,138 @@ +use connectrpc::async_trait; +use connectrpc::error::ConnectError; +use connectrpc::interceptor::{ + Interceptor, Next, NextStream, PayloadStream, StreamRequest, StreamResponse, UnaryRequest, + UnaryResponse, +}; +use std::time::Instant; + +#[derive(Debug, Clone, Default)] +pub struct LoggingInterceptor; + +impl LoggingInterceptor { + pub fn new() -> Self { + Self + } +} + +#[async_trait] +impl Interceptor for LoggingInterceptor { + async fn intercept_unary( + &self, + req: UnaryRequest, + next: Next<'_>, + ) -> Result { + let path = req.ctx.path().unwrap_or("unknown").to_string(); + let protocol = req + .ctx + .protocol() + .map(|p| format!("{p:?}")) + .unwrap_or_else(|| "unknown".into()); + let peer_addr = req + .ctx + .peer_addr() + .map(|p| p.to_string()) + .unwrap_or_else(|| "-".into()); + + let start = Instant::now(); + tracing::debug!( + target: "connectrpc::request", + path = %path, + protocol = %protocol, + peer = %peer_addr, + "unary request started" + ); + + let result = next.run(req).await; + let elapsed = start.elapsed(); + let elapsed_ms = elapsed.as_secs_f64() * 1000.0; + + match &result { + Ok(_) => { + tracing::info!( + target: "connectrpc::response", + path = %path, + protocol = %protocol, + peer = %peer_addr, + duration_ms = %format!("{:.2}ms", elapsed_ms), + status = "OK", + "unary RPC completed" + ); + } + Err(err) => { + tracing::error!( + target: "connectrpc::response", + path = %path, + protocol = %protocol, + peer = %peer_addr, + duration_ms = %format!("{:.2}ms", elapsed_ms), + code = ?err.code, + error = %err.message.as_deref().unwrap_or("no message"), + "unary RPC failed" + ); + } + } + + result + } + + async fn intercept_streaming( + &self, + req: StreamRequest, + inbound: PayloadStream, + next: NextStream<'_>, + ) -> Result { + let path = req.ctx.path().unwrap_or("unknown").to_string(); + let protocol = req + .ctx + .protocol() + .map(|p| format!("{p:?}")) + .unwrap_or_else(|| "unknown".into()); + let peer_addr = req + .ctx + .peer_addr() + .map(|p| p.to_string()) + .unwrap_or_else(|| "-".into()); + + let start = Instant::now(); + tracing::info!( + target: "connectrpc::stream", + path = %path, + protocol = %protocol, + peer = %peer_addr, + "streaming RPC connected" + ); + + let result = next.run(req, inbound).await; + let elapsed = start.elapsed(); + let elapsed_ms = elapsed.as_secs_f64() * 1000.0; + + match &result { + Ok(_) => { + tracing::info!( + target: "connectrpc::stream", + path = %path, + protocol = %protocol, + peer = %peer_addr, + duration_ms = %format!("{:.2}ms", elapsed_ms), + status = "OK", + "streaming RPC established" + ); + } + Err(err) => { + tracing::error!( + target: "connectrpc::stream", + path = %path, + protocol = %protocol, + peer = %peer_addr, + duration_ms = %format!("{:.2}ms", elapsed_ms), + code = ?err.code, + error = %err.message.as_deref().unwrap_or("no message"), + "streaming RPC failed establishment" + ); + } + } + + result + } +} diff --git a/backend/src/middleware/mod.rs b/backend/src/middleware/mod.rs new file mode 100644 index 0000000..a63d3b3 --- /dev/null +++ b/backend/src/middleware/mod.rs @@ -0,0 +1,5 @@ +pub mod auth; +pub mod logging; + +pub use auth::{AuthContextExt, AuthInterceptor}; +pub use logging::LoggingInterceptor; diff --git a/backend/src/models.rs b/backend/src/models.rs new file mode 100644 index 0000000..47d764a --- /dev/null +++ b/backend/src/models.rs @@ -0,0 +1,783 @@ +#![allow(unused_imports)] + +use crate::schema::sql_types::{ + BookCondition as SqlBookCondition, BookPictureType as SqlBookPictureType, + BookStatus as SqlBookStatus, LocationType as SqlLocationType, + PaymentMethod as SqlPaymentMethod, PaymentStatus as SqlPaymentStatus, + PaymentType as SqlPaymentType, TransactionStatus as SqlTransactionStatus, + VerificationDocumentType as SqlVerificationDocumentType, +}; +use crate::schema::{ + book_categories, book_pictures, book_purchases, books, boosts, conversation_messages, + conversations, donations, indexed_locations, meetup_locations, notification_bodies, + notification_template_translations, notification_templates, notifications, payment_intents, + payments, reviews, transactions, uploads, user_sessions, users, verification_documents, + wishlist_items, +}; +use bigdecimal::BigDecimal; +use chrono::{DateTime, Utc}; +use diesel::deserialize::{self, FromSql, FromSqlRow}; +use diesel::expression::AsExpression; +use diesel::pg::{Pg, PgValue}; +use diesel::prelude::*; +use diesel::serialize::{self, IsNull, Output, ToSql}; +use serde::{Deserialize, Serialize}; +use serde_json::Value as JsonValue; +use std::io::Write; +use uuid::Uuid; + +// ============================================================================= +// ENUMS +// ============================================================================= + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlLocationType)] +pub enum LocationType { + Book, + Meetup, +} + +impl ToSql for LocationType { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + LocationType::Book => out.write_all(b"book")?, + LocationType::Meetup => out.write_all(b"meetup")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for LocationType { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"book" => Ok(LocationType::Book), + b"meetup" => Ok(LocationType::Meetup), + _ => Err("Unrecognized enum variant for LocationType".into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlBookCondition)] +pub enum BookCondition { + New, + LikeNew, + Good, + Fair, + Poor, +} + +impl ToSql for BookCondition { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + BookCondition::New => out.write_all(b"new")?, + BookCondition::LikeNew => out.write_all(b"like_new")?, + BookCondition::Good => out.write_all(b"good")?, + BookCondition::Fair => out.write_all(b"fair")?, + BookCondition::Poor => out.write_all(b"poor")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for BookCondition { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"new" => Ok(BookCondition::New), + b"like_new" => Ok(BookCondition::LikeNew), + b"good" => Ok(BookCondition::Good), + b"fair" => Ok(BookCondition::Fair), + b"poor" => Ok(BookCondition::Poor), + _ => Err("Unrecognized enum variant for BookCondition".into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlBookPictureType)] +pub enum BookPictureType { + Front, + Back, + Other, +} + +impl ToSql for BookPictureType { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + BookPictureType::Front => out.write_all(b"front")?, + BookPictureType::Back => out.write_all(b"back")?, + BookPictureType::Other => out.write_all(b"other")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for BookPictureType { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"front" => Ok(BookPictureType::Front), + b"back" => Ok(BookPictureType::Back), + b"other" => Ok(BookPictureType::Other), + _ => Err("Unrecognized enum variant for BookPictureType".into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlBookStatus)] +pub enum BookStatus { + Available, + Sold, + Reserved, + Expired, + Removed, +} + +impl ToSql for BookStatus { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + BookStatus::Available => out.write_all(b"available")?, + BookStatus::Sold => out.write_all(b"sold")?, + BookStatus::Reserved => out.write_all(b"reserved")?, + BookStatus::Expired => out.write_all(b"expired")?, + BookStatus::Removed => out.write_all(b"removed")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for BookStatus { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"available" => Ok(BookStatus::Available), + b"sold" => Ok(BookStatus::Sold), + b"reserved" => Ok(BookStatus::Reserved), + b"expired" => Ok(BookStatus::Expired), + b"removed" => Ok(BookStatus::Removed), + _ => Err("Unrecognized enum variant for BookStatus".into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlPaymentType)] +pub enum PaymentType { + Book, + Donation, + Boost, +} + +impl ToSql for PaymentType { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + PaymentType::Book => out.write_all(b"book")?, + PaymentType::Donation => out.write_all(b"donation")?, + PaymentType::Boost => out.write_all(b"boost")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for PaymentType { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"book" => Ok(PaymentType::Book), + b"donation" => Ok(PaymentType::Donation), + b"boost" => Ok(PaymentType::Boost), + _ => Err("Unrecognized enum variant for PaymentType".into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlPaymentStatus)] +pub enum PaymentStatus { + Pending, + Completed, + Failed, +} + +impl ToSql for PaymentStatus { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + PaymentStatus::Pending => out.write_all(b"pending")?, + PaymentStatus::Completed => out.write_all(b"completed")?, + PaymentStatus::Failed => out.write_all(b"failed")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for PaymentStatus { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"pending" => Ok(PaymentStatus::Pending), + b"completed" => Ok(PaymentStatus::Completed), + b"failed" => Ok(PaymentStatus::Failed), + _ => Err("Unrecognized enum variant for PaymentStatus".into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlPaymentMethod)] +pub enum PaymentMethod { + Fapshi, +} + +impl ToSql for PaymentMethod { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + PaymentMethod::Fapshi => out.write_all(b"fapshi")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for PaymentMethod { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"fapshi" => Ok(PaymentMethod::Fapshi), + _ => Err("Unrecognized enum variant for PaymentMethod".into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlTransactionStatus)] +pub enum TransactionStatus { + Held, + Released, + Refunded, + Disputed, +} + +impl ToSql for TransactionStatus { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + TransactionStatus::Held => out.write_all(b"held")?, + TransactionStatus::Released => out.write_all(b"released")?, + TransactionStatus::Refunded => out.write_all(b"refunded")?, + TransactionStatus::Disputed => out.write_all(b"disputed")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for TransactionStatus { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"held" => Ok(TransactionStatus::Held), + b"released" => Ok(TransactionStatus::Released), + b"refunded" => Ok(TransactionStatus::Refunded), + b"disputed" => Ok(TransactionStatus::Disputed), + _ => Err("Unrecognized enum variant for TransactionStatus".into()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, AsExpression, FromSqlRow)] +#[diesel(sql_type = SqlVerificationDocumentType)] +pub enum VerificationDocumentType { + NationalId, + SchoolId, +} + +impl ToSql for VerificationDocumentType { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + match self { + VerificationDocumentType::NationalId => out.write_all(b"nationalid")?, + VerificationDocumentType::SchoolId => out.write_all(b"schoolid")?, + } + Ok(IsNull::No) + } +} + +impl FromSql for VerificationDocumentType { + fn from_sql(bytes: PgValue) -> deserialize::Result { + match bytes.as_bytes() { + b"nationalid" => Ok(VerificationDocumentType::NationalId), + b"schoolid" => Ok(VerificationDocumentType::SchoolId), + _ => Err("Unrecognized enum variant for VerificationDocumentType".into()), + } + } +} + +// ============================================================================= +// MODELS +// ============================================================================= + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = uploads)] +pub struct Upload { + pub id: Uuid, + pub storage_key: String, + pub file_name: String, + pub content_type: String, + pub size_bytes: i64, + pub uploaded_by: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = uploads)] +pub struct NewUpload { + pub id: Uuid, + pub storage_key: String, + pub file_name: String, + pub content_type: String, + pub size_bytes: i64, + pub uploaded_by: Option, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = users)] +pub struct User { + pub id: Uuid, + pub email: Option, + pub phone: String, + pub password_hash: Option, + pub first_name: String, + pub last_name: String, + pub avatar_id: Option, + pub rating: BigDecimal, + pub verified: bool, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = users)] +pub struct NewUser { + pub id: Uuid, + pub email: Option, + pub phone: String, + pub password_hash: Option, + pub first_name: String, + pub last_name: String, + pub avatar_id: Option, +} + +#[derive(Debug, Clone, Default, AsChangeset)] +#[diesel(table_name = users)] +pub struct UpdateUser { + pub email: Option>, + pub phone: Option, + pub password_hash: Option>, + pub first_name: Option, + pub last_name: Option, + pub avatar_id: Option>, + pub rating: Option, + pub verified: Option, + pub updated_at: Option>, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = user_sessions, primary_key(session_id))] +pub struct UserSession { + pub session_id: Uuid, + pub user_id: Uuid, + pub refresh_token_hash: Vec, + pub expires_at: DateTime, + pub rotated_at: DateTime, + pub fcm_token: Option, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = user_sessions)] +pub struct NewUserSession { + pub session_id: Uuid, + pub user_id: Uuid, + pub refresh_token_hash: Vec, + pub expires_at: DateTime, + pub fcm_token: Option, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = verification_documents, primary_key(user_id, upload_id))] +pub struct VerificationDocument { + pub user_id: Uuid, + pub upload_id: Uuid, + pub document_type: VerificationDocumentType, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = verification_documents)] +pub struct NewVerificationDocument { + pub user_id: Uuid, + pub upload_id: Uuid, + pub document_type: VerificationDocumentType, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = indexed_locations)] +pub struct IndexedLocation { + pub id: Uuid, + pub type_: LocationType, + pub latitude: f64, + pub longitude: f64, + pub h3_3: i64, + pub h3_4: i64, + pub h3_5: i64, + pub h3_6: i64, + pub h3_7: i64, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = indexed_locations)] +pub struct NewIndexedLocation { + pub id: Uuid, + pub type_: LocationType, + pub latitude: f64, + pub longitude: f64, + pub h3_3: i64, + pub h3_4: i64, + pub h3_5: i64, + pub h3_6: i64, + pub h3_7: i64, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = meetup_locations)] +pub struct MeetupLocation { + pub id: Uuid, + pub name: String, + pub description: Option, + pub location_id: Uuid, + pub verified: bool, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = meetup_locations)] +pub struct NewMeetupLocation { + pub id: Uuid, + pub name: String, + pub description: Option, + pub location_id: Uuid, + pub verified: bool, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = book_categories)] +pub struct BookCategory { + pub id: i64, + pub name: String, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = book_categories)] +pub struct NewBookCategory { + pub name: String, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = books)] +pub struct Book { + pub id: Uuid, + pub seller_id: Uuid, + pub ebook_id: Option, + pub title: String, + pub author: String, + pub price: i32, + pub condition: BookCondition, + pub description: Option, + pub status: BookStatus, + pub category: i64, + pub refundable: bool, + pub swapable: bool, + pub boost_expires_at: DateTime, + pub expires_at: DateTime, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, + pub location: Option, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = books)] +pub struct NewBook { + pub id: Uuid, + pub seller_id: Uuid, + pub ebook_id: Option, + pub title: String, + pub author: String, + pub price: i32, + pub condition: BookCondition, + pub description: Option, + pub status: BookStatus, + pub category: i64, + pub refundable: bool, + pub swapable: bool, + pub expires_at: DateTime, + pub location: Option, +} + +#[derive(Debug, Clone, Default, AsChangeset)] +#[diesel(table_name = books)] +pub struct UpdateBook { + pub title: Option, + pub author: Option, + pub price: Option, + pub condition: Option, + pub description: Option>, + pub status: Option, + pub category: Option, + pub refundable: Option, + pub swapable: Option, + pub location: Option>, + pub updated_at: Option>, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = book_pictures, primary_key(book_id, upload_id))] +pub struct BookPicture { + pub book_id: Uuid, + pub upload_id: Uuid, + pub type_: BookPictureType, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = book_pictures)] +pub struct NewBookPicture { + pub book_id: Uuid, + pub upload_id: Uuid, + pub type_: BookPictureType, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = conversations)] +pub struct Conversation { + pub id: Uuid, + pub book_id: Uuid, + pub user_id: Uuid, + pub created_at: DateTime, + pub deleted_at: Option>, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = conversations)] +pub struct NewConversation { + pub id: Uuid, + pub book_id: Uuid, + pub user_id: Uuid, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = conversation_messages)] +pub struct ConversationMessage { + pub id: Uuid, + pub user_id: Uuid, + pub conversation_id: Uuid, + pub content: String, + pub attachment: Option, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = conversation_messages)] +pub struct NewConversationMessage { + pub id: Uuid, + pub user_id: Uuid, + pub conversation_id: Uuid, + pub content: String, + pub attachment: Option, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = wishlist_items, primary_key(user_id, book_id))] +pub struct WishlistItem { + pub user_id: Uuid, + pub book_id: Uuid, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = wishlist_items)] +pub struct NewWishlistItem { + pub user_id: Uuid, + pub book_id: Uuid, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = notification_templates)] +pub struct NotificationTemplate { + pub id: Uuid, + pub parameters: JsonValue, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = notification_template_translations, primary_key(template_id, lang))] +pub struct NotificationTemplateTranslation { + pub template_id: Uuid, + pub lang: String, + pub format: String, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = notification_bodies)] +pub struct NotificationBody { + pub id: Uuid, + pub template_id: Uuid, + pub template_arguments: JsonValue, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = notifications)] +pub struct Notification { + pub id: Uuid, + pub user_id: Option, + pub body_id: Option, + pub template_arguments: JsonValue, + pub read_at: Option>, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = notifications)] +pub struct NewNotification { + pub id: Uuid, + pub user_id: Option, + pub body_id: Option, + pub template_arguments: JsonValue, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = reviews)] +pub struct Review { + pub id: Uuid, + pub author_id: Uuid, + pub reviewee_id: Option, + pub transaction_id: Option, + pub rating: BigDecimal, + pub content: Option, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = reviews)] +pub struct NewReview { + pub id: Uuid, + pub author_id: Uuid, + pub reviewee_id: Option, + pub transaction_id: Option, + pub rating: BigDecimal, + pub content: Option, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = payment_intents)] +pub struct PaymentIntent { + pub id: Uuid, + pub user_id: Uuid, + pub method: PaymentMethod, + pub amount: i32, + pub status: PaymentStatus, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = payment_intents)] +pub struct NewPaymentIntent { + pub id: Uuid, + pub user_id: Uuid, + pub method: PaymentMethod, + pub amount: i32, + pub status: PaymentStatus, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = payments, primary_key(intent_id))] +pub struct Payment { + pub intent_id: Uuid, + pub platform_transaction_reference: String, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = payments)] +pub struct NewPayment { + pub intent_id: Uuid, + pub platform_transaction_reference: String, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = transactions, primary_key(payment_id))] +pub struct Transaction { + pub payment_id: Uuid, + pub recipient: Uuid, + pub transaction_status: TransactionStatus, + pub created_at: DateTime, + pub updated_at: DateTime, + pub refunded_at: Option>, + pub deleted_at: Option>, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = transactions)] +pub struct NewTransaction { + pub payment_id: Uuid, + pub recipient: Uuid, + pub transaction_status: TransactionStatus, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = boosts, primary_key(payment_id))] +pub struct Boost { + pub payment_id: Uuid, + pub book_id: Uuid, + pub created_at: DateTime, + pub expires_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = boosts)] +pub struct NewBoost { + pub payment_id: Uuid, + pub book_id: Uuid, + pub expires_at: DateTime, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = donations, primary_key(payment_id))] +pub struct Donation { + pub payment_id: Uuid, + pub user_id: Option, + pub message: Option, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = donations)] +pub struct NewDonation { + pub payment_id: Uuid, + pub user_id: Option, + pub message: Option, +} + +#[derive(Debug, Clone, Queryable, Selectable, Identifiable, Serialize, Deserialize)] +#[diesel(table_name = book_purchases, primary_key(transaction_id))] +pub struct BookPurchase { + pub transaction_id: Uuid, + pub book_id: Uuid, + pub meetup_location: Option, + pub confirmed: bool, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Insertable)] +#[diesel(table_name = book_purchases)] +pub struct NewBookPurchase { + pub transaction_id: Uuid, + pub book_id: Uuid, + pub meetup_location: Option, + pub confirmed: bool, +} diff --git a/backend/src/proto/buf/bookbridge.v1.rs b/backend/src/proto/buf/bookbridge.v1.rs new file mode 100644 index 0000000..a83af2e --- /dev/null +++ b/backend/src/proto/buf/bookbridge.v1.rs @@ -0,0 +1,67372 @@ +// @generated by buffa-codegen. DO NOT EDIT. + +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct User { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `email` + #[serde( + rename = "email", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub email: ::buffa::alloc::string::String, + /// Field 3: `phone` + #[serde( + rename = "phone", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub phone: ::buffa::alloc::string::String, + /// Field 4: `first_name` + #[serde( + rename = "firstName", + alias = "first_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub first_name: ::buffa::alloc::string::String, + /// Field 5: `last_name` + #[serde( + rename = "lastName", + alias = "last_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub last_name: ::buffa::alloc::string::String, + /// Field 6: `avatar_url` + #[serde( + rename = "avatarUrl", + alias = "avatar_url", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub avatar_url: ::buffa::alloc::string::String, + /// Field 7: `rating` + #[serde( + rename = "rating", + with = "::buffa::json_helpers::double", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_f64" + )] + pub rating: f64, + /// Field 8: `verified` + #[serde( + rename = "verified", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub verified: bool, + /// Field 9: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 10: `updated_at` + #[serde( + rename = "updatedAt", + alias = "updated_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub updated_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for User { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("User") + .field("id", &self.id) + .field("email", &self.email) + .field("phone", &self.phone) + .field("first_name", &self.first_name) + .field("last_name", &self.last_name) + .field("avatar_url", &self.avatar_url) + .field("rating", &self.rating) + .field("verified", &self.verified) + .field("created_at", &self.created_at) + .field("updated_at", &self.updated_at) + .finish() + } +} +impl User { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.User"; +} +::buffa::impl_default_instance!(User); +impl ::buffa::MessageName for User { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "User"; + const FULL_NAME: &'static str = "bookbridge.v1.User"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.User"; +} +impl ::buffa::Message for User { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.email.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.email) as u64; + } + if !self.phone.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.phone) as u64; + } + if !self.first_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.first_name) as u64; + } + if !self.last_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.last_name) as u64; + } + if !self.avatar_url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.avatar_url) as u64; + } + if self.rating.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + if self.verified { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.updated_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.updated_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.email.is_empty() { + ::buffa::types::put_string_field(2u32, &self.email, buf); + } + if !self.phone.is_empty() { + ::buffa::types::put_string_field(3u32, &self.phone, buf); + } + if !self.first_name.is_empty() { + ::buffa::types::put_string_field(4u32, &self.first_name, buf); + } + if !self.last_name.is_empty() { + ::buffa::types::put_string_field(5u32, &self.last_name, buf); + } + if !self.avatar_url.is_empty() { + ::buffa::types::put_string_field(6u32, &self.avatar_url, buf); + } + if self.rating.to_bits() != 0u64 { + ::buffa::types::put_double_field(7u32, self.rating, buf); + } + if self.verified { + ::buffa::types::put_bool_field(8u32, self.verified, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 9u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + if self.updated_at.is_set() { + ::buffa::types::put_len_delimited_header( + 10u32, + u64::from(__cache.consume_next()), + buf, + ); + self.updated_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.email, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.phone, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.first_name, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.last_name, buf)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.avatar_url, buf)?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + self.rating = ::buffa::types::decode_double(buf)?; + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.verified = ::buffa::types::decode_bool(buf)?; + } + 9u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.updated_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.email.clear(); + self.phone.clear(); + self.first_name.clear(); + self.last_name.clear(); + self.avatar_url.clear(); + self.rating = 0f64; + self.verified = false; + self.created_at = ::buffa::MessageField::none(); + self.updated_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for User { + const PROTO_FQN: &'static str = "bookbridge.v1.User"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for User { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __USER_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.User", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Session { + /// Field 1: `session_id` + #[serde( + rename = "sessionId", + alias = "session_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub session_id: ::buffa::alloc::string::String, + /// Field 2: `user` + #[serde( + rename = "user", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub user: ::buffa::MessageField>, + /// Field 3: `access_token` + #[serde( + rename = "accessToken", + alias = "access_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub access_token: ::buffa::alloc::string::String, + /// Field 4: `refresh_token` + #[serde( + rename = "refreshToken", + alias = "refresh_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub refresh_token: ::buffa::alloc::string::String, + /// Field 5: `access_token_expires_at` + #[serde( + rename = "accessTokenExpiresAt", + alias = "access_token_expires_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub access_token_expires_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 6: `expires_at` + #[serde( + rename = "expiresAt", + alias = "expires_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub expires_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Session { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Session") + .field("session_id", &self.session_id) + .field("user", &self.user) + .field("access_token", &self.access_token) + .field("refresh_token", &self.refresh_token) + .field("access_token_expires_at", &self.access_token_expires_at) + .field("expires_at", &self.expires_at) + .finish() + } +} +impl Session { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Session"; +} +::buffa::impl_default_instance!(Session); +impl ::buffa::MessageName for Session { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Session"; + const FULL_NAME: &'static str = "bookbridge.v1.Session"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Session"; +} +impl ::buffa::Message for Session { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.session_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.session_id) as u64; + } + if self.user.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.user.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.access_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.access_token) as u64; + } + if !self.refresh_token.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.refresh_token) as u64; + } + if self.access_token_expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.access_token_expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.session_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.session_id, buf); + } + if self.user.is_set() { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + self.user.write_to(__cache, buf); + } + if !self.access_token.is_empty() { + ::buffa::types::put_string_field(3u32, &self.access_token, buf); + } + if !self.refresh_token.is_empty() { + ::buffa::types::put_string_field(4u32, &self.refresh_token, buf); + } + if self.access_token_expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.access_token_expires_at.write_to(__cache, buf); + } + if self.expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.expires_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.session_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.user.get_or_insert_default(), + buf, + ctx, + )?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.access_token, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.refresh_token, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.access_token_expires_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.expires_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.session_id.clear(); + self.user = ::buffa::MessageField::none(); + self.access_token.clear(); + self.refresh_token.clear(); + self.access_token_expires_at = ::buffa::MessageField::none(); + self.expires_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Session { + const PROTO_FQN: &'static str = "bookbridge.v1.Session"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Session { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SESSION_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Session", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SignUpRequest { + /// Field 1: `email` + #[serde( + rename = "email", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub email: ::buffa::alloc::string::String, + /// Field 2: `phone` + #[serde( + rename = "phone", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub phone: ::buffa::alloc::string::String, + /// Field 3: `password` + #[serde( + rename = "password", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub password: ::buffa::alloc::string::String, + /// Field 4: `first_name` + #[serde( + rename = "firstName", + alias = "first_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub first_name: ::buffa::alloc::string::String, + /// Field 5: `last_name` + #[serde( + rename = "lastName", + alias = "last_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub last_name: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SignUpRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SignUpRequest") + .field("email", &self.email) + .field("phone", &self.phone) + .field("password", &self.password) + .field("first_name", &self.first_name) + .field("last_name", &self.last_name) + .finish() + } +} +impl SignUpRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignUpRequest"; +} +::buffa::impl_default_instance!(SignUpRequest); +impl ::buffa::MessageName for SignUpRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignUpRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SignUpRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignUpRequest"; +} +impl ::buffa::Message for SignUpRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.email.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.email) as u64; + } + if !self.phone.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.phone) as u64; + } + if !self.password.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.password) as u64; + } + if !self.first_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.first_name) as u64; + } + if !self.last_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.last_name) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.email.is_empty() { + ::buffa::types::put_string_field(1u32, &self.email, buf); + } + if !self.phone.is_empty() { + ::buffa::types::put_string_field(2u32, &self.phone, buf); + } + if !self.password.is_empty() { + ::buffa::types::put_string_field(3u32, &self.password, buf); + } + if !self.first_name.is_empty() { + ::buffa::types::put_string_field(4u32, &self.first_name, buf); + } + if !self.last_name.is_empty() { + ::buffa::types::put_string_field(5u32, &self.last_name, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.email, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.phone, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.password, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.first_name, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.last_name, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.email.clear(); + self.phone.clear(); + self.password.clear(); + self.first_name.clear(); + self.last_name.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SignUpRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.SignUpRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SignUpRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SIGN_UP_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SignUpRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SignUpResponse { + /// Field 1: `session` + #[serde( + rename = "session", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub session: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SignUpResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SignUpResponse").field("session", &self.session).finish() + } +} +impl SignUpResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignUpResponse"; +} +::buffa::impl_default_instance!(SignUpResponse); +impl ::buffa::MessageName for SignUpResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignUpResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SignUpResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignUpResponse"; +} +impl ::buffa::Message for SignUpResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.session.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.session.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.session.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.session.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.session.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.session = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SignUpResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.SignUpResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SignUpResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SIGN_UP_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SignUpResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize)] +#[serde(default)] +pub struct SignInRequest { + /// Field 3: `password` + #[serde( + rename = "password", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub password: ::buffa::alloc::string::String, + #[serde(flatten)] + pub identifier: ::core::option::Option<__buffa::oneof::sign_in_request::Identifier>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SignInRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SignInRequest") + .field("password", &self.password) + .field("identifier", &self.identifier) + .finish() + } +} +impl SignInRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInRequest"; +} +::buffa::impl_default_instance!(SignInRequest); +impl ::buffa::MessageName for SignInRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignInRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SignInRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInRequest"; +} +impl ::buffa::Message for SignInRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if let ::core::option::Option::Some(ref v) = self.identifier { + match v { + __buffa::oneof::sign_in_request::Identifier::Email(x) => { + size += 1u64 + ::buffa::types::string_encoded_len(x) as u64; + } + __buffa::oneof::sign_in_request::Identifier::Phone(x) => { + size += 1u64 + ::buffa::types::string_encoded_len(x) as u64; + } + } + } + if !self.password.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.password) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let ::core::option::Option::Some(ref v) = self.identifier { + match v { + __buffa::oneof::sign_in_request::Identifier::Email(x) => { + ::buffa::types::put_string_field(1u32, x, buf); + } + __buffa::oneof::sign_in_request::Identifier::Phone(x) => { + ::buffa::types::put_string_field(2u32, x, buf); + } + } + } + if !self.password.is_empty() { + ::buffa::types::put_string_field(3u32, &self.password, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + self.identifier = ::core::option::Option::Some( + __buffa::oneof::sign_in_request::Identifier::Email( + ::buffa::types::decode_string(buf)?, + ), + ); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + self.identifier = ::core::option::Option::Some( + __buffa::oneof::sign_in_request::Identifier::Phone( + ::buffa::types::decode_string(buf)?, + ), + ); + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.password, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.identifier = ::core::option::Option::None; + self.password.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SignInRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.SignInRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl<'de> ::serde::Deserialize<'de> for SignInRequest { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl<'de> ::serde::de::Visitor<'de> for _V { + type Value = SignInRequest; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str("struct SignInRequest") + } + #[allow(clippy::field_reassign_with_default)] + fn visit_map>( + self, + mut map: A, + ) -> ::core::result::Result { + let mut __f_password: ::core::option::Option< + ::buffa::alloc::string::String, + > = None; + let mut __oneof_identifier: ::core::option::Option< + __buffa::oneof::sign_in_request::Identifier, + > = None; + while let Some(key) = map.next_key::<::buffa::alloc::string::String>()? { + match key.as_str() { + "password" => { + __f_password = Some({ + struct _S; + impl<'de> ::serde::de::DeserializeSeed<'de> for _S { + type Value = ::buffa::alloc::string::String; + fn deserialize>( + self, + d: D, + ) -> ::core::result::Result< + ::buffa::alloc::string::String, + D::Error, + > { + ::buffa::json_helpers::proto_string::deserialize(d) + } + } + map.next_value_seed(_S)? + }); + } + "email" => { + let v: ::core::option::Option< + ::buffa::alloc::string::String, + > = map + .next_value_seed( + ::buffa::json_helpers::NullableDeserializeSeed( + ::buffa::json_helpers::DefaultDeserializeSeed::< + ::buffa::alloc::string::String, + >::new(), + ), + )?; + if let Some(v) = v { + if __oneof_identifier.is_some() { + return Err( + ::serde::de::Error::custom( + "multiple oneof fields set for 'identifier'", + ), + ); + } + __oneof_identifier = Some( + __buffa::oneof::sign_in_request::Identifier::Email(v), + ); + } + } + "phone" => { + let v: ::core::option::Option< + ::buffa::alloc::string::String, + > = map + .next_value_seed( + ::buffa::json_helpers::NullableDeserializeSeed( + ::buffa::json_helpers::DefaultDeserializeSeed::< + ::buffa::alloc::string::String, + >::new(), + ), + )?; + if let Some(v) = v { + if __oneof_identifier.is_some() { + return Err( + ::serde::de::Error::custom( + "multiple oneof fields set for 'identifier'", + ), + ); + } + __oneof_identifier = Some( + __buffa::oneof::sign_in_request::Identifier::Phone(v), + ); + } + } + _ => { + map.next_value::<::serde::de::IgnoredAny>()?; + } + } + } + let mut __r = ::default(); + if let ::core::option::Option::Some(v) = __f_password { + __r.password = v; + } + __r.identifier = __oneof_identifier; + Ok(__r) + } + } + d.deserialize_map(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for SignInRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SIGN_IN_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SignInRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +pub mod sign_in_request { + #[allow(unused_imports)] + use super::*; + #[doc(inline)] + pub use super::__buffa::oneof::sign_in_request::Identifier; + #[doc(inline)] + pub use super::__buffa::view::oneof::sign_in_request::Identifier as IdentifierView; +} +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SignInResponse { + /// Field 1: `session` + #[serde( + rename = "session", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub session: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SignInResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SignInResponse").field("session", &self.session).finish() + } +} +impl SignInResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInResponse"; +} +::buffa::impl_default_instance!(SignInResponse); +impl ::buffa::MessageName for SignInResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignInResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SignInResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInResponse"; +} +impl ::buffa::Message for SignInResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.session.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.session.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.session.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.session.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.session.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.session = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SignInResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.SignInResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SignInResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SIGN_IN_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SignInResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SignInWithGoogleRequest { + /// Field 1: `id_token` + #[serde( + rename = "idToken", + alias = "id_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SignInWithGoogleRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SignInWithGoogleRequest") + .field("id_token", &self.id_token) + .finish() + } +} +impl SignInWithGoogleRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInWithGoogleRequest"; +} +::buffa::impl_default_instance!(SignInWithGoogleRequest); +impl ::buffa::MessageName for SignInWithGoogleRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignInWithGoogleRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SignInWithGoogleRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInWithGoogleRequest"; +} +impl ::buffa::Message for SignInWithGoogleRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SignInWithGoogleRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.SignInWithGoogleRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SignInWithGoogleRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SIGN_IN_WITH_GOOGLE_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SignInWithGoogleRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SignInWithGoogleResponse { + /// Field 1: `session` + #[serde( + rename = "session", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub session: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SignInWithGoogleResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SignInWithGoogleResponse") + .field("session", &self.session) + .finish() + } +} +impl SignInWithGoogleResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInWithGoogleResponse"; +} +::buffa::impl_default_instance!(SignInWithGoogleResponse); +impl ::buffa::MessageName for SignInWithGoogleResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignInWithGoogleResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SignInWithGoogleResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInWithGoogleResponse"; +} +impl ::buffa::Message for SignInWithGoogleResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.session.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.session.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.session.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.session.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.session.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.session = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SignInWithGoogleResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.SignInWithGoogleResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SignInWithGoogleResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SIGN_IN_WITH_GOOGLE_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SignInWithGoogleResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct RefreshSessionRequest { + /// The opaque refresh token issued with the current session. + /// + /// Field 1: `refresh_token` + #[serde( + rename = "refreshToken", + alias = "refresh_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub refresh_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for RefreshSessionRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("RefreshSessionRequest") + .field("refresh_token", &self.refresh_token) + .finish() + } +} +impl RefreshSessionRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RefreshSessionRequest"; +} +::buffa::impl_default_instance!(RefreshSessionRequest); +impl ::buffa::MessageName for RefreshSessionRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "RefreshSessionRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.RefreshSessionRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RefreshSessionRequest"; +} +impl ::buffa::Message for RefreshSessionRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.refresh_token.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.refresh_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.refresh_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.refresh_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.refresh_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.refresh_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for RefreshSessionRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.RefreshSessionRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for RefreshSessionRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __REFRESH_SESSION_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.RefreshSessionRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct RefreshSessionResponse { + /// New session with a fresh access token and a rotated refresh token; + /// the presented refresh token is invalidated. + /// + /// Field 1: `session` + #[serde( + rename = "session", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub session: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for RefreshSessionResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("RefreshSessionResponse").field("session", &self.session).finish() + } +} +impl RefreshSessionResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RefreshSessionResponse"; +} +::buffa::impl_default_instance!(RefreshSessionResponse); +impl ::buffa::MessageName for RefreshSessionResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "RefreshSessionResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.RefreshSessionResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RefreshSessionResponse"; +} +impl ::buffa::Message for RefreshSessionResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.session.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.session.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.session.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.session.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.session.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.session = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for RefreshSessionResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.RefreshSessionResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for RefreshSessionResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __REFRESH_SESSION_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.RefreshSessionResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SignOutRequest { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SignOutRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SignOutRequest").finish() + } +} +impl SignOutRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignOutRequest"; +} +::buffa::impl_default_instance!(SignOutRequest); +impl ::buffa::MessageName for SignOutRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignOutRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SignOutRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignOutRequest"; +} +impl ::buffa::Message for SignOutRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SignOutRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.SignOutRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SignOutRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SIGN_OUT_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SignOutRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SignOutResponse { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SignOutResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SignOutResponse").finish() + } +} +impl SignOutResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignOutResponse"; +} +::buffa::impl_default_instance!(SignOutResponse); +impl ::buffa::MessageName for SignOutResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignOutResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SignOutResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignOutResponse"; +} +impl ::buffa::Message for SignOutResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SignOutResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.SignOutResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SignOutResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SIGN_OUT_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SignOutResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetCurrentUserRequest { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetCurrentUserRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetCurrentUserRequest").finish() + } +} +impl GetCurrentUserRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetCurrentUserRequest"; +} +::buffa::impl_default_instance!(GetCurrentUserRequest); +impl ::buffa::MessageName for GetCurrentUserRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetCurrentUserRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetCurrentUserRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetCurrentUserRequest"; +} +impl ::buffa::Message for GetCurrentUserRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetCurrentUserRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetCurrentUserRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetCurrentUserRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_CURRENT_USER_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetCurrentUserRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetCurrentUserResponse { + /// Field 1: `user` + #[serde( + rename = "user", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub user: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetCurrentUserResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetCurrentUserResponse").field("user", &self.user).finish() + } +} +impl GetCurrentUserResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetCurrentUserResponse"; +} +::buffa::impl_default_instance!(GetCurrentUserResponse); +impl ::buffa::MessageName for GetCurrentUserResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetCurrentUserResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetCurrentUserResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetCurrentUserResponse"; +} +impl ::buffa::Message for GetCurrentUserResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.user.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.user.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.user.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.user.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.user.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.user = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetCurrentUserResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetCurrentUserResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetCurrentUserResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_CURRENT_USER_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetCurrentUserResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct UpdateCurrentUserRequest { + /// Field 1: `email` + #[serde(rename = "email", skip_serializing_if = "::core::option::Option::is_none")] + pub email: ::core::option::Option<::buffa::alloc::string::String>, + /// Field 2: `first_name` + #[serde( + rename = "firstName", + alias = "first_name", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub first_name: ::core::option::Option<::buffa::alloc::string::String>, + /// Field 3: `last_name` + #[serde( + rename = "lastName", + alias = "last_name", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub last_name: ::core::option::Option<::buffa::alloc::string::String>, + /// Field 4: `avatar_upload_id` + #[serde( + rename = "avatarUploadId", + alias = "avatar_upload_id", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub avatar_upload_id: ::core::option::Option<::buffa::alloc::string::String>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for UpdateCurrentUserRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("UpdateCurrentUserRequest") + .field("email", &self.email) + .field("first_name", &self.first_name) + .field("last_name", &self.last_name) + .field("avatar_upload_id", &self.avatar_upload_id) + .finish() + } +} +impl UpdateCurrentUserRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateCurrentUserRequest"; +} +impl UpdateCurrentUserRequest { + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::email`] to `Some(value)`, consuming and returning `self`. + pub fn with_email( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.email = Some(value.into()); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::first_name`] to `Some(value)`, consuming and returning `self`. + pub fn with_first_name( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.first_name = Some(value.into()); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::last_name`] to `Some(value)`, consuming and returning `self`. + pub fn with_last_name( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.last_name = Some(value.into()); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::avatar_upload_id`] to `Some(value)`, consuming and returning `self`. + pub fn with_avatar_upload_id( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.avatar_upload_id = Some(value.into()); + self + } +} +::buffa::impl_default_instance!(UpdateCurrentUserRequest); +impl ::buffa::MessageName for UpdateCurrentUserRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UpdateCurrentUserRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.UpdateCurrentUserRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateCurrentUserRequest"; +} +impl ::buffa::Message for UpdateCurrentUserRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if let Some(ref v) = self.email { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(ref v) = self.first_name { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(ref v) = self.last_name { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(ref v) = self.avatar_upload_id { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let Some(ref v) = self.email { + ::buffa::types::put_string_field(1u32, v, buf); + } + if let Some(ref v) = self.first_name { + ::buffa::types::put_string_field(2u32, v, buf); + } + if let Some(ref v) = self.last_name { + ::buffa::types::put_string_field(3u32, v, buf); + } + if let Some(ref v) = self.avatar_upload_id { + ::buffa::types::put_string_field(4u32, v, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + self.email.get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + self + .first_name + .get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + self + .last_name + .get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + self + .avatar_upload_id + .get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.email = ::core::option::Option::None; + self.first_name = ::core::option::Option::None; + self.last_name = ::core::option::Option::None; + self.avatar_upload_id = ::core::option::Option::None; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for UpdateCurrentUserRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.UpdateCurrentUserRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for UpdateCurrentUserRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __UPDATE_CURRENT_USER_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.UpdateCurrentUserRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct UpdateCurrentUserResponse { + /// Field 1: `user` + #[serde( + rename = "user", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub user: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for UpdateCurrentUserResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("UpdateCurrentUserResponse").field("user", &self.user).finish() + } +} +impl UpdateCurrentUserResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateCurrentUserResponse"; +} +::buffa::impl_default_instance!(UpdateCurrentUserResponse); +impl ::buffa::MessageName for UpdateCurrentUserResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UpdateCurrentUserResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.UpdateCurrentUserResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateCurrentUserResponse"; +} +impl ::buffa::Message for UpdateCurrentUserResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.user.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.user.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.user.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.user.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.user.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.user = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for UpdateCurrentUserResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.UpdateCurrentUserResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for UpdateCurrentUserResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __UPDATE_CURRENT_USER_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.UpdateCurrentUserResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SendPasswordResetRequest { + /// Field 1: `email` + #[serde( + rename = "email", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub email: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SendPasswordResetRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SendPasswordResetRequest").field("email", &self.email).finish() + } +} +impl SendPasswordResetRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendPasswordResetRequest"; +} +::buffa::impl_default_instance!(SendPasswordResetRequest); +impl ::buffa::MessageName for SendPasswordResetRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SendPasswordResetRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SendPasswordResetRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendPasswordResetRequest"; +} +impl ::buffa::Message for SendPasswordResetRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.email.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.email) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.email.is_empty() { + ::buffa::types::put_string_field(1u32, &self.email, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.email, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.email.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SendPasswordResetRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.SendPasswordResetRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SendPasswordResetRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SEND_PASSWORD_RESET_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SendPasswordResetRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SendPasswordResetResponse { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SendPasswordResetResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SendPasswordResetResponse").finish() + } +} +impl SendPasswordResetResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendPasswordResetResponse"; +} +::buffa::impl_default_instance!(SendPasswordResetResponse); +impl ::buffa::MessageName for SendPasswordResetResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SendPasswordResetResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SendPasswordResetResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendPasswordResetResponse"; +} +impl ::buffa::Message for SendPasswordResetResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SendPasswordResetResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.SendPasswordResetResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SendPasswordResetResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SEND_PASSWORD_RESET_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SendPasswordResetResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Registers/updates the FCM token of the device tied to the current session +/// (maps to user_sessions.fcm_token). +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SetDeviceTokenRequest { + /// Field 1: `fcm_token` + #[serde( + rename = "fcmToken", + alias = "fcm_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub fcm_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SetDeviceTokenRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SetDeviceTokenRequest") + .field("fcm_token", &self.fcm_token) + .finish() + } +} +impl SetDeviceTokenRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SetDeviceTokenRequest"; +} +::buffa::impl_default_instance!(SetDeviceTokenRequest); +impl ::buffa::MessageName for SetDeviceTokenRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SetDeviceTokenRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SetDeviceTokenRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SetDeviceTokenRequest"; +} +impl ::buffa::Message for SetDeviceTokenRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.fcm_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.fcm_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.fcm_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.fcm_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.fcm_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.fcm_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SetDeviceTokenRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.SetDeviceTokenRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SetDeviceTokenRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SET_DEVICE_TOKEN_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SetDeviceTokenRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SetDeviceTokenResponse { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SetDeviceTokenResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SetDeviceTokenResponse").finish() + } +} +impl SetDeviceTokenResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SetDeviceTokenResponse"; +} +::buffa::impl_default_instance!(SetDeviceTokenResponse); +impl ::buffa::MessageName for SetDeviceTokenResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SetDeviceTokenResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SetDeviceTokenResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SetDeviceTokenResponse"; +} +impl ::buffa::Message for SetDeviceTokenResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SetDeviceTokenResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.SetDeviceTokenResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SetDeviceTokenResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SET_DEVICE_TOKEN_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SetDeviceTokenResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct LatLng { + /// Field 1: `latitude` + #[serde( + rename = "latitude", + with = "::buffa::json_helpers::double", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_f64" + )] + pub latitude: f64, + /// Field 2: `longitude` + #[serde( + rename = "longitude", + with = "::buffa::json_helpers::double", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_f64" + )] + pub longitude: f64, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for LatLng { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("LatLng") + .field("latitude", &self.latitude) + .field("longitude", &self.longitude) + .finish() + } +} +impl LatLng { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.LatLng"; +} +::buffa::impl_default_instance!(LatLng); +impl ::buffa::MessageName for LatLng { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "LatLng"; + const FULL_NAME: &'static str = "bookbridge.v1.LatLng"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.LatLng"; +} +impl ::buffa::Message for LatLng { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.latitude.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + if self.longitude.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.latitude.to_bits() != 0u64 { + ::buffa::types::put_double_field(1u32, self.latitude, buf); + } + if self.longitude.to_bits() != 0u64 { + ::buffa::types::put_double_field(2u32, self.longitude, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + self.latitude = ::buffa::types::decode_double(buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + self.longitude = ::buffa::types::decode_double(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.latitude = 0f64; + self.longitude = 0f64; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for LatLng { + const PROTO_FQN: &'static str = "bookbridge.v1.LatLng"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for LatLng { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LAT_LNG_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.LatLng", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Public-facing user info embedded in books, conversations, reviews, etc. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct UserSummary { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `first_name` + #[serde( + rename = "firstName", + alias = "first_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub first_name: ::buffa::alloc::string::String, + /// Field 3: `last_name` + #[serde( + rename = "lastName", + alias = "last_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub last_name: ::buffa::alloc::string::String, + /// Field 4: `avatar_url` + #[serde( + rename = "avatarUrl", + alias = "avatar_url", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub avatar_url: ::buffa::alloc::string::String, + /// Field 5: `rating` + #[serde( + rename = "rating", + with = "::buffa::json_helpers::double", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_f64" + )] + pub rating: f64, + /// Field 6: `verified` + #[serde( + rename = "verified", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub verified: bool, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for UserSummary { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("UserSummary") + .field("id", &self.id) + .field("first_name", &self.first_name) + .field("last_name", &self.last_name) + .field("avatar_url", &self.avatar_url) + .field("rating", &self.rating) + .field("verified", &self.verified) + .finish() + } +} +impl UserSummary { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UserSummary"; +} +::buffa::impl_default_instance!(UserSummary); +impl ::buffa::MessageName for UserSummary { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UserSummary"; + const FULL_NAME: &'static str = "bookbridge.v1.UserSummary"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UserSummary"; +} +impl ::buffa::Message for UserSummary { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.first_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.first_name) as u64; + } + if !self.last_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.last_name) as u64; + } + if !self.avatar_url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.avatar_url) as u64; + } + if self.rating.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + if self.verified { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.first_name.is_empty() { + ::buffa::types::put_string_field(2u32, &self.first_name, buf); + } + if !self.last_name.is_empty() { + ::buffa::types::put_string_field(3u32, &self.last_name, buf); + } + if !self.avatar_url.is_empty() { + ::buffa::types::put_string_field(4u32, &self.avatar_url, buf); + } + if self.rating.to_bits() != 0u64 { + ::buffa::types::put_double_field(5u32, self.rating, buf); + } + if self.verified { + ::buffa::types::put_bool_field(6u32, self.verified, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.first_name, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.last_name, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.avatar_url, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + self.rating = ::buffa::types::decode_double(buf)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.verified = ::buffa::types::decode_bool(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.first_name.clear(); + self.last_name.clear(); + self.avatar_url.clear(); + self.rating = 0f64; + self.verified = false; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for UserSummary { + const PROTO_FQN: &'static str = "bookbridge.v1.UserSummary"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for UserSummary { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __USER_SUMMARY_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.UserSummary", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(i32)] +pub enum BookCondition { + BOOK_CONDITION_UNSPECIFIED = 0i32, + BOOK_CONDITION_NEW = 1i32, + BOOK_CONDITION_LIKE_NEW = 2i32, + BOOK_CONDITION_GOOD = 3i32, + BOOK_CONDITION_FAIR = 4i32, + BOOK_CONDITION_POOR = 5i32, +} +impl BookCondition { + ///Idiomatic alias for [`Self::BOOK_CONDITION_UNSPECIFIED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Unspecified: Self = Self::BOOK_CONDITION_UNSPECIFIED; + ///Idiomatic alias for [`Self::BOOK_CONDITION_NEW`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const New: Self = Self::BOOK_CONDITION_NEW; + ///Idiomatic alias for [`Self::BOOK_CONDITION_LIKE_NEW`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const LikeNew: Self = Self::BOOK_CONDITION_LIKE_NEW; + ///Idiomatic alias for [`Self::BOOK_CONDITION_GOOD`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Good: Self = Self::BOOK_CONDITION_GOOD; + ///Idiomatic alias for [`Self::BOOK_CONDITION_FAIR`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Fair: Self = Self::BOOK_CONDITION_FAIR; + ///Idiomatic alias for [`Self::BOOK_CONDITION_POOR`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Poor: Self = Self::BOOK_CONDITION_POOR; +} +impl ::core::default::Default for BookCondition { + fn default() -> Self { + Self::BOOK_CONDITION_UNSPECIFIED + } +} +impl ::serde::Serialize for BookCondition { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + s.serialize_str(::buffa::Enumeration::proto_name(self)) + } +} +impl<'de> ::serde::Deserialize<'de> for BookCondition { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl ::serde::de::Visitor<'_> for _V { + type Value = BookCondition; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str( + concat!("a string, integer, or null for ", stringify!(BookCondition)), + ) + } + fn visit_str( + self, + v: &str, + ) -> ::core::result::Result { + ::from_proto_name(v) + .ok_or_else(|| { ::serde::de::Error::unknown_variant(v, &[]) }) + } + fn visit_i64( + self, + v: i64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_u64( + self, + v: u64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_unit( + self, + ) -> ::core::result::Result { + ::core::result::Result::Ok(::core::default::Default::default()) + } + } + d.deserialize_any(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for BookCondition { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +impl ::buffa::Enumeration for BookCondition { + fn from_i32(value: i32) -> ::core::option::Option { + match value { + 0i32 => ::core::option::Option::Some(Self::BOOK_CONDITION_UNSPECIFIED), + 1i32 => ::core::option::Option::Some(Self::BOOK_CONDITION_NEW), + 2i32 => ::core::option::Option::Some(Self::BOOK_CONDITION_LIKE_NEW), + 3i32 => ::core::option::Option::Some(Self::BOOK_CONDITION_GOOD), + 4i32 => ::core::option::Option::Some(Self::BOOK_CONDITION_FAIR), + 5i32 => ::core::option::Option::Some(Self::BOOK_CONDITION_POOR), + _ => ::core::option::Option::None, + } + } + fn to_i32(&self) -> i32 { + *self as i32 + } + fn proto_name(&self) -> &'static str { + match self { + Self::BOOK_CONDITION_UNSPECIFIED => "BOOK_CONDITION_UNSPECIFIED", + Self::BOOK_CONDITION_NEW => "BOOK_CONDITION_NEW", + Self::BOOK_CONDITION_LIKE_NEW => "BOOK_CONDITION_LIKE_NEW", + Self::BOOK_CONDITION_GOOD => "BOOK_CONDITION_GOOD", + Self::BOOK_CONDITION_FAIR => "BOOK_CONDITION_FAIR", + Self::BOOK_CONDITION_POOR => "BOOK_CONDITION_POOR", + } + } + fn from_proto_name(name: &str) -> ::core::option::Option { + match name { + "BOOK_CONDITION_UNSPECIFIED" => { + ::core::option::Option::Some(Self::BOOK_CONDITION_UNSPECIFIED) + } + "BOOK_CONDITION_NEW" => { + ::core::option::Option::Some(Self::BOOK_CONDITION_NEW) + } + "BOOK_CONDITION_LIKE_NEW" => { + ::core::option::Option::Some(Self::BOOK_CONDITION_LIKE_NEW) + } + "BOOK_CONDITION_GOOD" => { + ::core::option::Option::Some(Self::BOOK_CONDITION_GOOD) + } + "BOOK_CONDITION_FAIR" => { + ::core::option::Option::Some(Self::BOOK_CONDITION_FAIR) + } + "BOOK_CONDITION_POOR" => { + ::core::option::Option::Some(Self::BOOK_CONDITION_POOR) + } + _ => ::core::option::Option::None, + } + } + fn values() -> &'static [Self] { + &[ + Self::BOOK_CONDITION_UNSPECIFIED, + Self::BOOK_CONDITION_NEW, + Self::BOOK_CONDITION_LIKE_NEW, + Self::BOOK_CONDITION_GOOD, + Self::BOOK_CONDITION_FAIR, + Self::BOOK_CONDITION_POOR, + ] + } +} +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(i32)] +pub enum BookStatus { + BOOK_STATUS_UNSPECIFIED = 0i32, + BOOK_STATUS_AVAILABLE = 1i32, + BOOK_STATUS_SOLD = 2i32, + BOOK_STATUS_RESERVED = 3i32, + BOOK_STATUS_EXPIRED = 4i32, + BOOK_STATUS_REMOVED = 5i32, +} +impl BookStatus { + ///Idiomatic alias for [`Self::BOOK_STATUS_UNSPECIFIED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Unspecified: Self = Self::BOOK_STATUS_UNSPECIFIED; + ///Idiomatic alias for [`Self::BOOK_STATUS_AVAILABLE`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Available: Self = Self::BOOK_STATUS_AVAILABLE; + ///Idiomatic alias for [`Self::BOOK_STATUS_SOLD`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Sold: Self = Self::BOOK_STATUS_SOLD; + ///Idiomatic alias for [`Self::BOOK_STATUS_RESERVED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Reserved: Self = Self::BOOK_STATUS_RESERVED; + ///Idiomatic alias for [`Self::BOOK_STATUS_EXPIRED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Expired: Self = Self::BOOK_STATUS_EXPIRED; + ///Idiomatic alias for [`Self::BOOK_STATUS_REMOVED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Removed: Self = Self::BOOK_STATUS_REMOVED; +} +impl ::core::default::Default for BookStatus { + fn default() -> Self { + Self::BOOK_STATUS_UNSPECIFIED + } +} +impl ::serde::Serialize for BookStatus { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + s.serialize_str(::buffa::Enumeration::proto_name(self)) + } +} +impl<'de> ::serde::Deserialize<'de> for BookStatus { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl ::serde::de::Visitor<'_> for _V { + type Value = BookStatus; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str( + concat!("a string, integer, or null for ", stringify!(BookStatus)), + ) + } + fn visit_str( + self, + v: &str, + ) -> ::core::result::Result { + ::from_proto_name(v) + .ok_or_else(|| { ::serde::de::Error::unknown_variant(v, &[]) }) + } + fn visit_i64( + self, + v: i64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_u64( + self, + v: u64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_unit( + self, + ) -> ::core::result::Result { + ::core::result::Result::Ok(::core::default::Default::default()) + } + } + d.deserialize_any(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for BookStatus { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +impl ::buffa::Enumeration for BookStatus { + fn from_i32(value: i32) -> ::core::option::Option { + match value { + 0i32 => ::core::option::Option::Some(Self::BOOK_STATUS_UNSPECIFIED), + 1i32 => ::core::option::Option::Some(Self::BOOK_STATUS_AVAILABLE), + 2i32 => ::core::option::Option::Some(Self::BOOK_STATUS_SOLD), + 3i32 => ::core::option::Option::Some(Self::BOOK_STATUS_RESERVED), + 4i32 => ::core::option::Option::Some(Self::BOOK_STATUS_EXPIRED), + 5i32 => ::core::option::Option::Some(Self::BOOK_STATUS_REMOVED), + _ => ::core::option::Option::None, + } + } + fn to_i32(&self) -> i32 { + *self as i32 + } + fn proto_name(&self) -> &'static str { + match self { + Self::BOOK_STATUS_UNSPECIFIED => "BOOK_STATUS_UNSPECIFIED", + Self::BOOK_STATUS_AVAILABLE => "BOOK_STATUS_AVAILABLE", + Self::BOOK_STATUS_SOLD => "BOOK_STATUS_SOLD", + Self::BOOK_STATUS_RESERVED => "BOOK_STATUS_RESERVED", + Self::BOOK_STATUS_EXPIRED => "BOOK_STATUS_EXPIRED", + Self::BOOK_STATUS_REMOVED => "BOOK_STATUS_REMOVED", + } + } + fn from_proto_name(name: &str) -> ::core::option::Option { + match name { + "BOOK_STATUS_UNSPECIFIED" => { + ::core::option::Option::Some(Self::BOOK_STATUS_UNSPECIFIED) + } + "BOOK_STATUS_AVAILABLE" => { + ::core::option::Option::Some(Self::BOOK_STATUS_AVAILABLE) + } + "BOOK_STATUS_SOLD" => ::core::option::Option::Some(Self::BOOK_STATUS_SOLD), + "BOOK_STATUS_RESERVED" => { + ::core::option::Option::Some(Self::BOOK_STATUS_RESERVED) + } + "BOOK_STATUS_EXPIRED" => { + ::core::option::Option::Some(Self::BOOK_STATUS_EXPIRED) + } + "BOOK_STATUS_REMOVED" => { + ::core::option::Option::Some(Self::BOOK_STATUS_REMOVED) + } + _ => ::core::option::Option::None, + } + } + fn values() -> &'static [Self] { + &[ + Self::BOOK_STATUS_UNSPECIFIED, + Self::BOOK_STATUS_AVAILABLE, + Self::BOOK_STATUS_SOLD, + Self::BOOK_STATUS_RESERVED, + Self::BOOK_STATUS_EXPIRED, + Self::BOOK_STATUS_REMOVED, + ] + } +} +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(i32)] +pub enum BookPictureType { + BOOK_PICTURE_TYPE_UNSPECIFIED = 0i32, + BOOK_PICTURE_TYPE_FRONT = 1i32, + BOOK_PICTURE_TYPE_BACK = 2i32, + BOOK_PICTURE_TYPE_OTHER = 3i32, +} +impl BookPictureType { + ///Idiomatic alias for [`Self::BOOK_PICTURE_TYPE_UNSPECIFIED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Unspecified: Self = Self::BOOK_PICTURE_TYPE_UNSPECIFIED; + ///Idiomatic alias for [`Self::BOOK_PICTURE_TYPE_FRONT`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Front: Self = Self::BOOK_PICTURE_TYPE_FRONT; + ///Idiomatic alias for [`Self::BOOK_PICTURE_TYPE_BACK`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Back: Self = Self::BOOK_PICTURE_TYPE_BACK; + ///Idiomatic alias for [`Self::BOOK_PICTURE_TYPE_OTHER`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Other: Self = Self::BOOK_PICTURE_TYPE_OTHER; +} +impl ::core::default::Default for BookPictureType { + fn default() -> Self { + Self::BOOK_PICTURE_TYPE_UNSPECIFIED + } +} +impl ::serde::Serialize for BookPictureType { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + s.serialize_str(::buffa::Enumeration::proto_name(self)) + } +} +impl<'de> ::serde::Deserialize<'de> for BookPictureType { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl ::serde::de::Visitor<'_> for _V { + type Value = BookPictureType; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str( + concat!( + "a string, integer, or null for ", stringify!(BookPictureType) + ), + ) + } + fn visit_str( + self, + v: &str, + ) -> ::core::result::Result { + ::from_proto_name(v) + .ok_or_else(|| { ::serde::de::Error::unknown_variant(v, &[]) }) + } + fn visit_i64( + self, + v: i64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_u64( + self, + v: u64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_unit( + self, + ) -> ::core::result::Result { + ::core::result::Result::Ok(::core::default::Default::default()) + } + } + d.deserialize_any(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for BookPictureType { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +impl ::buffa::Enumeration for BookPictureType { + fn from_i32(value: i32) -> ::core::option::Option { + match value { + 0i32 => ::core::option::Option::Some(Self::BOOK_PICTURE_TYPE_UNSPECIFIED), + 1i32 => ::core::option::Option::Some(Self::BOOK_PICTURE_TYPE_FRONT), + 2i32 => ::core::option::Option::Some(Self::BOOK_PICTURE_TYPE_BACK), + 3i32 => ::core::option::Option::Some(Self::BOOK_PICTURE_TYPE_OTHER), + _ => ::core::option::Option::None, + } + } + fn to_i32(&self) -> i32 { + *self as i32 + } + fn proto_name(&self) -> &'static str { + match self { + Self::BOOK_PICTURE_TYPE_UNSPECIFIED => "BOOK_PICTURE_TYPE_UNSPECIFIED", + Self::BOOK_PICTURE_TYPE_FRONT => "BOOK_PICTURE_TYPE_FRONT", + Self::BOOK_PICTURE_TYPE_BACK => "BOOK_PICTURE_TYPE_BACK", + Self::BOOK_PICTURE_TYPE_OTHER => "BOOK_PICTURE_TYPE_OTHER", + } + } + fn from_proto_name(name: &str) -> ::core::option::Option { + match name { + "BOOK_PICTURE_TYPE_UNSPECIFIED" => { + ::core::option::Option::Some(Self::BOOK_PICTURE_TYPE_UNSPECIFIED) + } + "BOOK_PICTURE_TYPE_FRONT" => { + ::core::option::Option::Some(Self::BOOK_PICTURE_TYPE_FRONT) + } + "BOOK_PICTURE_TYPE_BACK" => { + ::core::option::Option::Some(Self::BOOK_PICTURE_TYPE_BACK) + } + "BOOK_PICTURE_TYPE_OTHER" => { + ::core::option::Option::Some(Self::BOOK_PICTURE_TYPE_OTHER) + } + _ => ::core::option::Option::None, + } + } + fn values() -> &'static [Self] { + &[ + Self::BOOK_PICTURE_TYPE_UNSPECIFIED, + Self::BOOK_PICTURE_TYPE_FRONT, + Self::BOOK_PICTURE_TYPE_BACK, + Self::BOOK_PICTURE_TYPE_OTHER, + ] + } +} +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct BookCategory { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub id: i64, + /// Field 2: `name` + #[serde( + rename = "name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub name: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for BookCategory { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("BookCategory") + .field("id", &self.id) + .field("name", &self.name) + .finish() + } +} +impl BookCategory { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookCategory"; +} +::buffa::impl_default_instance!(BookCategory); +impl ::buffa::MessageName for BookCategory { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "BookCategory"; + const FULL_NAME: &'static str = "bookbridge.v1.BookCategory"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookCategory"; +} +impl ::buffa::Message for BookCategory { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.id != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.id) as u64; + } + if !self.name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.name) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.id != 0i64 { + ::buffa::types::put_int64_field(1u32, self.id, buf); + } + if !self.name.is_empty() { + ::buffa::types::put_string_field(2u32, &self.name, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.id = ::buffa::types::decode_int64(buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.name, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id = 0i64; + self.name.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for BookCategory { + const PROTO_FQN: &'static str = "bookbridge.v1.BookCategory"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for BookCategory { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __BOOK_CATEGORY_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.BookCategory", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct BookPicture { + /// Field 1: `upload_id` + #[serde( + rename = "uploadId", + alias = "upload_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub upload_id: ::buffa::alloc::string::String, + /// Field 2: `url` + #[serde( + rename = "url", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub url: ::buffa::alloc::string::String, + /// Field 3: `type` + #[serde( + rename = "type", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub r#type: ::buffa::EnumValue, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for BookPicture { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("BookPicture") + .field("upload_id", &self.upload_id) + .field("url", &self.url) + .field("type", &self.r#type) + .finish() + } +} +impl BookPicture { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookPicture"; +} +::buffa::impl_default_instance!(BookPicture); +impl ::buffa::MessageName for BookPicture { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "BookPicture"; + const FULL_NAME: &'static str = "bookbridge.v1.BookPicture"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookPicture"; +} +impl ::buffa::Message for BookPicture { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + if !self.url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.url) as u64; + } + { + let val = self.r#type.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + if !self.url.is_empty() { + ::buffa::types::put_string_field(2u32, &self.url, buf); + } + { + let val = self.r#type.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(3u32, val, buf); + } + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.upload_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.url, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.r#type = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.upload_id.clear(); + self.url.clear(); + self.r#type = ::buffa::EnumValue::from(0); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for BookPicture { + const PROTO_FQN: &'static str = "bookbridge.v1.BookPicture"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for BookPicture { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __BOOK_PICTURE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.BookPicture", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Maps to the books table with its seller joined in. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Book { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `seller` + #[serde( + rename = "seller", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub seller: ::buffa::MessageField>, + /// Field 3: `title` + #[serde( + rename = "title", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub title: ::buffa::alloc::string::String, + /// Field 4: `author` + #[serde( + rename = "author", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub author: ::buffa::alloc::string::String, + /// Field 5: `price_fcfa` + #[serde( + rename = "priceFcfa", + alias = "price_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub price_fcfa: i64, + /// Field 6: `condition` + #[serde( + rename = "condition", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub condition: ::buffa::EnumValue, + /// Field 7: `description` + #[serde( + rename = "description", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub description: ::buffa::alloc::string::String, + /// Field 8: `status` + #[serde( + rename = "status", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub status: ::buffa::EnumValue, + /// Field 9: `category` + #[serde( + rename = "category", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub category: ::buffa::MessageField>, + /// Field 10: `refundable` + #[serde( + rename = "refundable", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub refundable: bool, + /// Field 11: `swapable` + #[serde( + rename = "swapable", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub swapable: bool, + /// Field 12: `pictures` + #[serde( + rename = "pictures", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub pictures: ::buffa::alloc::vec::Vec, + /// Field 13: `ebook_id` + #[serde( + rename = "ebookId", + alias = "ebook_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub ebook_id: ::buffa::alloc::string::String, + /// Field 14: `boost_expires_at` + #[serde( + rename = "boostExpiresAt", + alias = "boost_expires_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub boost_expires_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 15: `expires_at` + #[serde( + rename = "expiresAt", + alias = "expires_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub expires_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 16: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 17: `updated_at` + #[serde( + rename = "updatedAt", + alias = "updated_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub updated_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 18: `location` + #[serde( + rename = "location", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub location: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Book { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Book") + .field("id", &self.id) + .field("seller", &self.seller) + .field("title", &self.title) + .field("author", &self.author) + .field("price_fcfa", &self.price_fcfa) + .field("condition", &self.condition) + .field("description", &self.description) + .field("status", &self.status) + .field("category", &self.category) + .field("refundable", &self.refundable) + .field("swapable", &self.swapable) + .field("pictures", &self.pictures) + .field("ebook_id", &self.ebook_id) + .field("boost_expires_at", &self.boost_expires_at) + .field("expires_at", &self.expires_at) + .field("created_at", &self.created_at) + .field("updated_at", &self.updated_at) + .field("location", &self.location) + .finish() + } +} +impl Book { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Book"; +} +::buffa::impl_default_instance!(Book); +impl ::buffa::MessageName for Book { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Book"; + const FULL_NAME: &'static str = "bookbridge.v1.Book"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Book"; +} +impl ::buffa::Message for Book { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if self.seller.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.seller.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.title.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.author.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.author) as u64; + } + if self.price_fcfa != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.price_fcfa) as u64; + } + { + let val = self.condition.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if !self.description.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.description) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.category.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.category.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.refundable { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.swapable { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + for v in &self.pictures { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.ebook_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.ebook_id) as u64; + } + if self.boost_expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.boost_expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 2u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.updated_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.updated_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 2u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 2u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if self.seller.is_set() { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + self.seller.write_to(__cache, buf); + } + if !self.title.is_empty() { + ::buffa::types::put_string_field(3u32, &self.title, buf); + } + if !self.author.is_empty() { + ::buffa::types::put_string_field(4u32, &self.author, buf); + } + if self.price_fcfa != 0i64 { + ::buffa::types::put_int64_field(5u32, self.price_fcfa, buf); + } + { + let val = self.condition.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(6u32, val, buf); + } + } + if !self.description.is_empty() { + ::buffa::types::put_string_field(7u32, &self.description, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(8u32, val, buf); + } + } + if self.category.is_set() { + ::buffa::types::put_len_delimited_header( + 9u32, + u64::from(__cache.consume_next()), + buf, + ); + self.category.write_to(__cache, buf); + } + if self.refundable { + ::buffa::types::put_bool_field(10u32, self.refundable, buf); + } + if self.swapable { + ::buffa::types::put_bool_field(11u32, self.swapable, buf); + } + for v in &self.pictures { + ::buffa::types::put_len_delimited_header( + 12u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.ebook_id.is_empty() { + ::buffa::types::put_string_field(13u32, &self.ebook_id, buf); + } + if self.boost_expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 14u32, + u64::from(__cache.consume_next()), + buf, + ); + self.boost_expires_at.write_to(__cache, buf); + } + if self.expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 15u32, + u64::from(__cache.consume_next()), + buf, + ); + self.expires_at.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 16u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + if self.updated_at.is_set() { + ::buffa::types::put_len_delimited_header( + 17u32, + u64::from(__cache.consume_next()), + buf, + ); + self.updated_at.write_to(__cache, buf); + } + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 18u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.seller.get_or_insert_default(), + buf, + ctx, + )?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.title, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.author, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.price_fcfa = ::buffa::types::decode_int64(buf)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.condition = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.description, buf)?; + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 9u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.category.get_or_insert_default(), + buf, + ctx, + )?; + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.refundable = ::buffa::types::decode_bool(buf)?; + } + 11u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.swapable = ::buffa::types::decode_bool(buf)?; + } + 12u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.pictures.push(elem); + } + 13u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.ebook_id, buf)?; + } + 14u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.boost_expires_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 15u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.expires_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 16u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 17u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.updated_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 18u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.location.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.seller = ::buffa::MessageField::none(); + self.title.clear(); + self.author.clear(); + self.price_fcfa = 0i64; + self.condition = ::buffa::EnumValue::from(0); + self.description.clear(); + self.status = ::buffa::EnumValue::from(0); + self.category = ::buffa::MessageField::none(); + self.refundable = false; + self.swapable = false; + self.pictures.clear(); + self.ebook_id.clear(); + self.boost_expires_at = ::buffa::MessageField::none(); + self.expires_at = ::buffa::MessageField::none(); + self.created_at = ::buffa::MessageField::none(); + self.updated_at = ::buffa::MessageField::none(); + self.location = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Book { + const PROTO_FQN: &'static str = "bookbridge.v1.Book"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Book { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __BOOK_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Book", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListCategoriesRequest { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListCategoriesRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListCategoriesRequest").finish() + } +} +impl ListCategoriesRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListCategoriesRequest"; +} +::buffa::impl_default_instance!(ListCategoriesRequest); +impl ::buffa::MessageName for ListCategoriesRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListCategoriesRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListCategoriesRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListCategoriesRequest"; +} +impl ::buffa::Message for ListCategoriesRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListCategoriesRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListCategoriesRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListCategoriesRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_CATEGORIES_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListCategoriesRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListCategoriesResponse { + /// Field 1: `categories` + #[serde( + rename = "categories", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub categories: ::buffa::alloc::vec::Vec, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListCategoriesResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListCategoriesResponse") + .field("categories", &self.categories) + .finish() + } +} +impl ListCategoriesResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListCategoriesResponse"; +} +::buffa::impl_default_instance!(ListCategoriesResponse); +impl ::buffa::MessageName for ListCategoriesResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListCategoriesResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListCategoriesResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListCategoriesResponse"; +} +impl ::buffa::Message for ListCategoriesResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.categories { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.categories { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.categories.push(elem); + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.categories.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListCategoriesResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListCategoriesResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListCategoriesResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_CATEGORIES_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListCategoriesResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListBooksRequest { + /// Field 1: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 2: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + /// Field 3: `status` + #[serde( + rename = "status", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub status: ::buffa::EnumValue, + /// Field 4: `category_id` + #[serde( + rename = "categoryId", + alias = "category_id", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub category_id: i64, + /// Center for radius-based discovery (uses the indexed_locations H3 columns). + /// + /// Field 5: `center` + #[serde( + rename = "center", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub center: ::buffa::MessageField>, + /// Field 6: `radius_km` + #[serde( + rename = "radiusKm", + alias = "radius_km", + with = "::buffa::json_helpers::double", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_f64" + )] + pub radius_km: f64, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListBooksRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListBooksRequest") + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .field("status", &self.status) + .field("category_id", &self.category_id) + .field("center", &self.center) + .field("radius_km", &self.radius_km) + .finish() + } +} +impl ListBooksRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksRequest"; +} +::buffa::impl_default_instance!(ListBooksRequest); +impl ::buffa::MessageName for ListBooksRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListBooksRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListBooksRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksRequest"; +} +impl ::buffa::Message for ListBooksRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.category_id != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.category_id) as u64; + } + if self.center.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.center.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.radius_km.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(3u32, val, buf); + } + } + if self.category_id != 0i64 { + ::buffa::types::put_int64_field(4u32, self.category_id, buf); + } + if self.center.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.center.write_to(__cache, buf); + } + if self.radius_km.to_bits() != 0u64 { + ::buffa::types::put_double_field(6u32, self.radius_km, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.category_id = ::buffa::types::decode_int64(buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.center.get_or_insert_default(), + buf, + ctx, + )?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + self.radius_km = ::buffa::types::decode_double(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.page_token.clear(); + self.page_size = 0i32; + self.status = ::buffa::EnumValue::from(0); + self.category_id = 0i64; + self.center = ::buffa::MessageField::none(); + self.radius_km = 0f64; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListBooksRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListBooksRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListBooksRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_BOOKS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListBooksRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListBooksResponse { + /// Field 1: `books` + #[serde( + rename = "books", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub books: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListBooksResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListBooksResponse") + .field("books", &self.books) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListBooksResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksResponse"; +} +::buffa::impl_default_instance!(ListBooksResponse); +impl ::buffa::MessageName for ListBooksResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListBooksResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListBooksResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksResponse"; +} +impl ::buffa::Message for ListBooksResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.books.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.books.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListBooksResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListBooksResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListBooksResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_BOOKS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListBooksResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SearchBooksRequest { + /// Field 1: `query` + #[serde( + rename = "query", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub query: ::buffa::alloc::string::String, + /// Field 2: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 3: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + /// Field 4: `category_id` + #[serde( + rename = "categoryId", + alias = "category_id", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub category_id: i64, + /// Field 5: `center` + #[serde( + rename = "center", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub center: ::buffa::MessageField>, + /// Field 6: `radius_km` + #[serde( + rename = "radiusKm", + alias = "radius_km", + with = "::buffa::json_helpers::double", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_f64" + )] + pub radius_km: f64, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SearchBooksRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SearchBooksRequest") + .field("query", &self.query) + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .field("category_id", &self.category_id) + .field("center", &self.center) + .field("radius_km", &self.radius_km) + .finish() + } +} +impl SearchBooksRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SearchBooksRequest"; +} +::buffa::impl_default_instance!(SearchBooksRequest); +impl ::buffa::MessageName for SearchBooksRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SearchBooksRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SearchBooksRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SearchBooksRequest"; +} +impl ::buffa::Message for SearchBooksRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.query.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.query) as u64; + } + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + if self.category_id != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.category_id) as u64; + } + if self.center.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.center.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.radius_km.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.query.is_empty() { + ::buffa::types::put_string_field(1u32, &self.query, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(3u32, self.page_size, buf); + } + if self.category_id != 0i64 { + ::buffa::types::put_int64_field(4u32, self.category_id, buf); + } + if self.center.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.center.write_to(__cache, buf); + } + if self.radius_km.to_bits() != 0u64 { + ::buffa::types::put_double_field(6u32, self.radius_km, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.query, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.category_id = ::buffa::types::decode_int64(buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.center.get_or_insert_default(), + buf, + ctx, + )?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + self.radius_km = ::buffa::types::decode_double(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.query.clear(); + self.page_token.clear(); + self.page_size = 0i32; + self.category_id = 0i64; + self.center = ::buffa::MessageField::none(); + self.radius_km = 0f64; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SearchBooksRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.SearchBooksRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SearchBooksRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SEARCH_BOOKS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SearchBooksRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SearchBooksResponse { + /// Field 1: `books` + #[serde( + rename = "books", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub books: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SearchBooksResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SearchBooksResponse") + .field("books", &self.books) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl SearchBooksResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SearchBooksResponse"; +} +::buffa::impl_default_instance!(SearchBooksResponse); +impl ::buffa::MessageName for SearchBooksResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SearchBooksResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SearchBooksResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SearchBooksResponse"; +} +impl ::buffa::Message for SearchBooksResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.books.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.books.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SearchBooksResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.SearchBooksResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SearchBooksResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SEARCH_BOOKS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SearchBooksResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetBookRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetBookRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetBookRequest").field("book_id", &self.book_id).finish() + } +} +impl GetBookRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBookRequest"; +} +::buffa::impl_default_instance!(GetBookRequest); +impl ::buffa::MessageName for GetBookRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetBookRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetBookRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBookRequest"; +} +impl ::buffa::Message for GetBookRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetBookRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetBookRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetBookRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_BOOK_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetBookRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetBookResponse { + /// Field 1: `book` + #[serde( + rename = "book", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub book: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetBookResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetBookResponse").field("book", &self.book).finish() + } +} +impl GetBookResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBookResponse"; +} +::buffa::impl_default_instance!(GetBookResponse); +impl ::buffa::MessageName for GetBookResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetBookResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetBookResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBookResponse"; +} +impl ::buffa::Message for GetBookResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.book.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetBookResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetBookResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetBookResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_BOOK_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetBookResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListBooksBySellerRequest { + /// Field 1: `seller_id` + #[serde( + rename = "sellerId", + alias = "seller_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub seller_id: ::buffa::alloc::string::String, + /// Field 2: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 3: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListBooksBySellerRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListBooksBySellerRequest") + .field("seller_id", &self.seller_id) + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .finish() + } +} +impl ListBooksBySellerRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksBySellerRequest"; +} +::buffa::impl_default_instance!(ListBooksBySellerRequest); +impl ::buffa::MessageName for ListBooksBySellerRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListBooksBySellerRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListBooksBySellerRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksBySellerRequest"; +} +impl ::buffa::Message for ListBooksBySellerRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.seller_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.seller_id) as u64; + } + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.seller_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.seller_id, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(3u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.seller_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.seller_id.clear(); + self.page_token.clear(); + self.page_size = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListBooksBySellerRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListBooksBySellerRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListBooksBySellerRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_BOOKS_BY_SELLER_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListBooksBySellerRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListBooksBySellerResponse { + /// Field 1: `books` + #[serde( + rename = "books", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub books: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListBooksBySellerResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListBooksBySellerResponse") + .field("books", &self.books) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListBooksBySellerResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksBySellerResponse"; +} +::buffa::impl_default_instance!(ListBooksBySellerResponse); +impl ::buffa::MessageName for ListBooksBySellerResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListBooksBySellerResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListBooksBySellerResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksBySellerResponse"; +} +impl ::buffa::Message for ListBooksBySellerResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.books.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.books.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListBooksBySellerResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListBooksBySellerResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListBooksBySellerResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_BOOKS_BY_SELLER_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListBooksBySellerResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMyBooksRequest { + /// Field 1: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 2: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + /// Field 3: `status` + #[serde( + rename = "status", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub status: ::buffa::EnumValue, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMyBooksRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMyBooksRequest") + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .field("status", &self.status) + .finish() + } +} +impl ListMyBooksRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyBooksRequest"; +} +::buffa::impl_default_instance!(ListMyBooksRequest); +impl ::buffa::MessageName for ListMyBooksRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMyBooksRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMyBooksRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyBooksRequest"; +} +impl ::buffa::Message for ListMyBooksRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(3u32, val, buf); + } + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.page_token.clear(); + self.page_size = 0i32; + self.status = ::buffa::EnumValue::from(0); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMyBooksRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMyBooksRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMyBooksRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MY_BOOKS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMyBooksRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMyBooksResponse { + /// Field 1: `books` + #[serde( + rename = "books", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub books: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMyBooksResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMyBooksResponse") + .field("books", &self.books) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListMyBooksResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyBooksResponse"; +} +::buffa::impl_default_instance!(ListMyBooksResponse); +impl ::buffa::MessageName for ListMyBooksResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMyBooksResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMyBooksResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyBooksResponse"; +} +impl ::buffa::Message for ListMyBooksResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.books.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.books.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMyBooksResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMyBooksResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMyBooksResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MY_BOOKS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMyBooksResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateBookRequest { + /// Field 1: `title` + #[serde( + rename = "title", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub title: ::buffa::alloc::string::String, + /// Field 2: `author` + #[serde( + rename = "author", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub author: ::buffa::alloc::string::String, + /// Field 3: `price_fcfa` + #[serde( + rename = "priceFcfa", + alias = "price_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub price_fcfa: i64, + /// Field 4: `condition` + #[serde( + rename = "condition", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub condition: ::buffa::EnumValue, + /// Field 5: `description` + #[serde( + rename = "description", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub description: ::buffa::alloc::string::String, + /// Field 6: `category_id` + #[serde( + rename = "categoryId", + alias = "category_id", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub category_id: i64, + /// Field 7: `refundable` + #[serde( + rename = "refundable", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub refundable: bool, + /// Field 8: `swapable` + #[serde( + rename = "swapable", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub swapable: bool, + /// Field 9: `picture_upload_ids` + #[serde( + rename = "pictureUploadIds", + alias = "picture_upload_ids", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub picture_upload_ids: ::buffa::alloc::vec::Vec<::buffa::alloc::string::String>, + /// Field 10: `picture_types` + #[serde( + rename = "pictureTypes", + alias = "picture_types", + with = "::buffa::json_helpers::map_enum", + skip_serializing_if = "::buffa::__private::HashMap::is_empty" + )] + pub picture_types: ::buffa::__private::HashMap< + ::buffa::alloc::string::String, + ::buffa::EnumValue, + >, + /// Field 11: `ebook_upload_id` + #[serde( + rename = "ebookUploadId", + alias = "ebook_upload_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub ebook_upload_id: ::buffa::alloc::string::String, + /// Field 12: `location` + #[serde( + rename = "location", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub location: ::buffa::MessageField>, + /// Listing expiry in days from creation; server assigns a default when unset. + /// + /// Field 13: `expires_in_days` + #[serde( + rename = "expiresInDays", + alias = "expires_in_days", + with = "::buffa::json_helpers::opt_int32", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub expires_in_days: ::core::option::Option, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateBookRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateBookRequest") + .field("title", &self.title) + .field("author", &self.author) + .field("price_fcfa", &self.price_fcfa) + .field("condition", &self.condition) + .field("description", &self.description) + .field("category_id", &self.category_id) + .field("refundable", &self.refundable) + .field("swapable", &self.swapable) + .field("picture_upload_ids", &self.picture_upload_ids) + .field("picture_types", &self.picture_types) + .field("ebook_upload_id", &self.ebook_upload_id) + .field("location", &self.location) + .field("expires_in_days", &self.expires_in_days) + .finish() + } +} +impl CreateBookRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookRequest"; +} +impl CreateBookRequest { + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::expires_in_days`] to `Some(value)`, consuming and returning `self`. + pub fn with_expires_in_days(mut self, value: i32) -> Self { + self.expires_in_days = Some(value); + self + } +} +::buffa::impl_default_instance!(CreateBookRequest); +impl ::buffa::MessageName for CreateBookRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBookRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBookRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookRequest"; +} +impl ::buffa::Message for CreateBookRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.title.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.author.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.author) as u64; + } + if self.price_fcfa != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.price_fcfa) as u64; + } + { + let val = self.condition.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if !self.description.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.description) as u64; + } + if self.category_id != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.category_id) as u64; + } + if self.refundable { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.swapable { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + for v in &self.picture_upload_ids { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + size + += ::buffa::map_codec::field_len::< + ::buffa::map_codec::Str, + ::buffa::map_codec::OpenEnum<_>, + _, + >(&self.picture_types, 1u64); + if !self.ebook_upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.ebook_upload_id) as u64; + } + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if let Some(v) = self.expires_in_days { + size += 1u64 + ::buffa::types::int32_encoded_len(v) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.title.is_empty() { + ::buffa::types::put_string_field(1u32, &self.title, buf); + } + if !self.author.is_empty() { + ::buffa::types::put_string_field(2u32, &self.author, buf); + } + if self.price_fcfa != 0i64 { + ::buffa::types::put_int64_field(3u32, self.price_fcfa, buf); + } + { + let val = self.condition.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(4u32, val, buf); + } + } + if !self.description.is_empty() { + ::buffa::types::put_string_field(5u32, &self.description, buf); + } + if self.category_id != 0i64 { + ::buffa::types::put_int64_field(6u32, self.category_id, buf); + } + if self.refundable { + ::buffa::types::put_bool_field(7u32, self.refundable, buf); + } + if self.swapable { + ::buffa::types::put_bool_field(8u32, self.swapable, buf); + } + for v in &self.picture_upload_ids { + ::buffa::types::put_string_field(9u32, v, buf); + } + ::buffa::map_codec::write_field::< + ::buffa::map_codec::Str, + ::buffa::map_codec::OpenEnum<_>, + _, + >(&self.picture_types, 10u32, buf); + if !self.ebook_upload_id.is_empty() { + ::buffa::types::put_string_field(11u32, &self.ebook_upload_id, buf); + } + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 12u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + if let Some(v) = self.expires_in_days { + ::buffa::types::put_int32_field(13u32, v, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.title, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.author, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.price_fcfa = ::buffa::types::decode_int64(buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.condition = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.description, buf)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.category_id = ::buffa::types::decode_int64(buf)?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.refundable = ::buffa::types::decode_bool(buf)?; + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.swapable = ::buffa::types::decode_bool(buf)?; + } + 9u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __elem = ::buffa::types::decode_string(buf)?; + ctx.register_element_memory( + ::buffa::__private::element_footprint(&__elem), + )?; + self.picture_upload_ids.push(__elem); + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::map_codec::merge_entry::< + ::buffa::map_codec::Str, + ::buffa::map_codec::OpenEnum<_>, + _, + >(&mut self.picture_types, buf, ctx)?; + } + 11u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.ebook_upload_id, buf)?; + } + 12u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.location.get_or_insert_default(), + buf, + ctx, + )?; + } + 13u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.expires_in_days = ::core::option::Option::Some( + ::buffa::types::decode_int32(buf)?, + ); + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.title.clear(); + self.author.clear(); + self.price_fcfa = 0i64; + self.condition = ::buffa::EnumValue::from(0); + self.description.clear(); + self.category_id = 0i64; + self.refundable = false; + self.swapable = false; + self.picture_upload_ids.clear(); + self.picture_types.clear(); + self.ebook_upload_id.clear(); + self.location = ::buffa::MessageField::none(); + self.expires_in_days = ::core::option::Option::None; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateBookRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateBookRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateBookRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_BOOK_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateBookRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateBookResponse { + /// Field 1: `book` + #[serde( + rename = "book", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub book: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateBookResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateBookResponse").field("book", &self.book).finish() + } +} +impl CreateBookResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookResponse"; +} +::buffa::impl_default_instance!(CreateBookResponse); +impl ::buffa::MessageName for CreateBookResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBookResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBookResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookResponse"; +} +impl ::buffa::Message for CreateBookResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.book.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateBookResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateBookResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateBookResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_BOOK_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateBookResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct UpdateBookRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + /// Field 2: `title` + #[serde(rename = "title", skip_serializing_if = "::core::option::Option::is_none")] + pub title: ::core::option::Option<::buffa::alloc::string::String>, + /// Field 3: `author` + #[serde(rename = "author", skip_serializing_if = "::core::option::Option::is_none")] + pub author: ::core::option::Option<::buffa::alloc::string::String>, + /// Field 4: `price_fcfa` + #[serde( + rename = "priceFcfa", + alias = "price_fcfa", + with = "::buffa::json_helpers::opt_int64", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub price_fcfa: ::core::option::Option, + /// Field 5: `condition` + #[serde( + rename = "condition", + with = "::buffa::json_helpers::opt_enum", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub condition: ::core::option::Option<::buffa::EnumValue>, + /// Field 6: `description` + #[serde( + rename = "description", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub description: ::core::option::Option<::buffa::alloc::string::String>, + /// Field 7: `category_id` + #[serde( + rename = "categoryId", + alias = "category_id", + with = "::buffa::json_helpers::opt_int64", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub category_id: ::core::option::Option, + /// Field 8: `refundable` + #[serde( + rename = "refundable", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub refundable: ::core::option::Option, + /// Field 9: `swapable` + #[serde( + rename = "swapable", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub swapable: ::core::option::Option, + /// Field 10: `status` + #[serde( + rename = "status", + with = "::buffa::json_helpers::opt_enum", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub status: ::core::option::Option<::buffa::EnumValue>, + /// Field 11: `picture_upload_ids` + #[serde( + rename = "pictureUploadIds", + alias = "picture_upload_ids", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub picture_upload_ids: ::buffa::alloc::vec::Vec<::buffa::alloc::string::String>, + /// Field 12: `picture_types` + #[serde( + rename = "pictureTypes", + alias = "picture_types", + with = "::buffa::json_helpers::map_enum", + skip_serializing_if = "::buffa::__private::HashMap::is_empty" + )] + pub picture_types: ::buffa::__private::HashMap< + ::buffa::alloc::string::String, + ::buffa::EnumValue, + >, + /// Field 13: `location` + #[serde( + rename = "location", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub location: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for UpdateBookRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("UpdateBookRequest") + .field("book_id", &self.book_id) + .field("title", &self.title) + .field("author", &self.author) + .field("price_fcfa", &self.price_fcfa) + .field("condition", &self.condition) + .field("description", &self.description) + .field("category_id", &self.category_id) + .field("refundable", &self.refundable) + .field("swapable", &self.swapable) + .field("status", &self.status) + .field("picture_upload_ids", &self.picture_upload_ids) + .field("picture_types", &self.picture_types) + .field("location", &self.location) + .finish() + } +} +impl UpdateBookRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateBookRequest"; +} +impl UpdateBookRequest { + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::title`] to `Some(value)`, consuming and returning `self`. + pub fn with_title( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.title = Some(value.into()); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::author`] to `Some(value)`, consuming and returning `self`. + pub fn with_author( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.author = Some(value.into()); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::price_fcfa`] to `Some(value)`, consuming and returning `self`. + pub fn with_price_fcfa(mut self, value: i64) -> Self { + self.price_fcfa = Some(value); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::condition`] to `Some(value)`, consuming and returning `self`. + pub fn with_condition( + mut self, + value: impl Into<::buffa::EnumValue>, + ) -> Self { + self.condition = Some(value.into()); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::description`] to `Some(value)`, consuming and returning `self`. + pub fn with_description( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.description = Some(value.into()); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::category_id`] to `Some(value)`, consuming and returning `self`. + pub fn with_category_id(mut self, value: i64) -> Self { + self.category_id = Some(value); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::refundable`] to `Some(value)`, consuming and returning `self`. + pub fn with_refundable(mut self, value: bool) -> Self { + self.refundable = Some(value); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::swapable`] to `Some(value)`, consuming and returning `self`. + pub fn with_swapable(mut self, value: bool) -> Self { + self.swapable = Some(value); + self + } + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::status`] to `Some(value)`, consuming and returning `self`. + pub fn with_status( + mut self, + value: impl Into<::buffa::EnumValue>, + ) -> Self { + self.status = Some(value.into()); + self + } +} +::buffa::impl_default_instance!(UpdateBookRequest); +impl ::buffa::MessageName for UpdateBookRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UpdateBookRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.UpdateBookRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateBookRequest"; +} +impl ::buffa::Message for UpdateBookRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if let Some(ref v) = self.title { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(ref v) = self.author { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(v) = self.price_fcfa { + size += 1u64 + ::buffa::types::int64_encoded_len(v) as u64; + } + if let Some(ref v) = self.condition { + size += 1u64 + ::buffa::types::int32_encoded_len(v.to_i32()) as u64; + } + if let Some(ref v) = self.description { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(v) = self.category_id { + size += 1u64 + ::buffa::types::int64_encoded_len(v) as u64; + } + if self.refundable.is_some() { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.swapable.is_some() { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if let Some(ref v) = self.status { + size += 1u64 + ::buffa::types::int32_encoded_len(v.to_i32()) as u64; + } + for v in &self.picture_upload_ids { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + size + += ::buffa::map_codec::field_len::< + ::buffa::map_codec::Str, + ::buffa::map_codec::OpenEnum<_>, + _, + >(&self.picture_types, 1u64); + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + if let Some(ref v) = self.title { + ::buffa::types::put_string_field(2u32, v, buf); + } + if let Some(ref v) = self.author { + ::buffa::types::put_string_field(3u32, v, buf); + } + if let Some(v) = self.price_fcfa { + ::buffa::types::put_int64_field(4u32, v, buf); + } + if let Some(ref v) = self.condition { + ::buffa::types::put_int32_field(5u32, v.to_i32(), buf); + } + if let Some(ref v) = self.description { + ::buffa::types::put_string_field(6u32, v, buf); + } + if let Some(v) = self.category_id { + ::buffa::types::put_int64_field(7u32, v, buf); + } + if let Some(v) = self.refundable { + ::buffa::types::put_bool_field(8u32, v, buf); + } + if let Some(v) = self.swapable { + ::buffa::types::put_bool_field(9u32, v, buf); + } + if let Some(ref v) = self.status { + ::buffa::types::put_int32_field(10u32, v.to_i32(), buf); + } + for v in &self.picture_upload_ids { + ::buffa::types::put_string_field(11u32, v, buf); + } + ::buffa::map_codec::write_field::< + ::buffa::map_codec::Str, + ::buffa::map_codec::OpenEnum<_>, + _, + >(&self.picture_types, 12u32, buf); + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 13u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + self.title.get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + self.author.get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.price_fcfa = ::core::option::Option::Some( + ::buffa::types::decode_int64(buf)?, + ); + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.condition = ::core::option::Option::Some( + ::buffa::EnumValue::from(::buffa::types::decode_int32(buf)?), + ); + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + self + .description + .get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.category_id = ::core::option::Option::Some( + ::buffa::types::decode_int64(buf)?, + ); + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.refundable = ::core::option::Option::Some( + ::buffa::types::decode_bool(buf)?, + ); + } + 9u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.swapable = ::core::option::Option::Some( + ::buffa::types::decode_bool(buf)?, + ); + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.status = ::core::option::Option::Some( + ::buffa::EnumValue::from(::buffa::types::decode_int32(buf)?), + ); + } + 11u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __elem = ::buffa::types::decode_string(buf)?; + ctx.register_element_memory( + ::buffa::__private::element_footprint(&__elem), + )?; + self.picture_upload_ids.push(__elem); + } + 12u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::map_codec::merge_entry::< + ::buffa::map_codec::Str, + ::buffa::map_codec::OpenEnum<_>, + _, + >(&mut self.picture_types, buf, ctx)?; + } + 13u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.location.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.title = ::core::option::Option::None; + self.author = ::core::option::Option::None; + self.price_fcfa = ::core::option::Option::None; + self.condition = ::core::option::Option::None; + self.description = ::core::option::Option::None; + self.category_id = ::core::option::Option::None; + self.refundable = ::core::option::Option::None; + self.swapable = ::core::option::Option::None; + self.status = ::core::option::Option::None; + self.picture_upload_ids.clear(); + self.picture_types.clear(); + self.location = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for UpdateBookRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.UpdateBookRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for UpdateBookRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __UPDATE_BOOK_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.UpdateBookRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct UpdateBookResponse { + /// Field 1: `book` + #[serde( + rename = "book", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub book: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for UpdateBookResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("UpdateBookResponse").field("book", &self.book).finish() + } +} +impl UpdateBookResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateBookResponse"; +} +::buffa::impl_default_instance!(UpdateBookResponse); +impl ::buffa::MessageName for UpdateBookResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UpdateBookResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.UpdateBookResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateBookResponse"; +} +impl ::buffa::Message for UpdateBookResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.book.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for UpdateBookResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.UpdateBookResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for UpdateBookResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __UPDATE_BOOK_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.UpdateBookResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct DeleteBookRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for DeleteBookRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DeleteBookRequest").field("book_id", &self.book_id).finish() + } +} +impl DeleteBookRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteBookRequest"; +} +::buffa::impl_default_instance!(DeleteBookRequest); +impl ::buffa::MessageName for DeleteBookRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DeleteBookRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.DeleteBookRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteBookRequest"; +} +impl ::buffa::Message for DeleteBookRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for DeleteBookRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.DeleteBookRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for DeleteBookRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DELETE_BOOK_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.DeleteBookRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct DeleteBookResponse { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for DeleteBookResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DeleteBookResponse").finish() + } +} +impl DeleteBookResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteBookResponse"; +} +::buffa::impl_default_instance!(DeleteBookResponse); +impl ::buffa::MessageName for DeleteBookResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DeleteBookResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.DeleteBookResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteBookResponse"; +} +impl ::buffa::Message for DeleteBookResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for DeleteBookResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.DeleteBookResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for DeleteBookResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DELETE_BOOK_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.DeleteBookResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Maps to the boosts table (payment_type = boost). +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Boost { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + /// Field 3: `amount_fcfa` + #[serde( + rename = "amountFcfa", + alias = "amount_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub amount_fcfa: i64, + /// Field 4: `expires_at` + #[serde( + rename = "expiresAt", + alias = "expires_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub expires_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 5: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Boost { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Boost") + .field("id", &self.id) + .field("book_id", &self.book_id) + .field("amount_fcfa", &self.amount_fcfa) + .field("expires_at", &self.expires_at) + .field("created_at", &self.created_at) + .finish() + } +} +impl Boost { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Boost"; +} +::buffa::impl_default_instance!(Boost); +impl ::buffa::MessageName for Boost { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Boost"; + const FULL_NAME: &'static str = "bookbridge.v1.Boost"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Boost"; +} +impl ::buffa::Message for Boost { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if self.amount_fcfa != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + if self.expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.book_id, buf); + } + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(3u32, self.amount_fcfa, buf); + } + if self.expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 4u32, + u64::from(__cache.consume_next()), + buf, + ); + self.expires_at.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.amount_fcfa = ::buffa::types::decode_int64(buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.expires_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.book_id.clear(); + self.amount_fcfa = 0i64; + self.expires_at = ::buffa::MessageField::none(); + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Boost { + const PROTO_FQN: &'static str = "bookbridge.v1.Boost"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Boost { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __BOOST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Boost", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateBoostRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + /// Field 2: `amount_fcfa` + #[serde( + rename = "amountFcfa", + alias = "amount_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub amount_fcfa: i64, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateBoostRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateBoostRequest") + .field("book_id", &self.book_id) + .field("amount_fcfa", &self.amount_fcfa) + .finish() + } +} +impl CreateBoostRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBoostRequest"; +} +::buffa::impl_default_instance!(CreateBoostRequest); +impl ::buffa::MessageName for CreateBoostRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBoostRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBoostRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBoostRequest"; +} +impl ::buffa::Message for CreateBoostRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if self.amount_fcfa != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(2u32, self.amount_fcfa, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.amount_fcfa = ::buffa::types::decode_int64(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.amount_fcfa = 0i64; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateBoostRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateBoostRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateBoostRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_BOOST_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateBoostRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateBoostResponse { + /// Field 1: `boost` + #[serde( + rename = "boost", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub boost: ::buffa::MessageField>, + /// Field 2: `fapshi_transaction_id` + #[serde( + rename = "fapshiTransactionId", + alias = "fapshi_transaction_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub fapshi_transaction_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateBoostResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateBoostResponse") + .field("boost", &self.boost) + .field("fapshi_transaction_id", &self.fapshi_transaction_id) + .finish() + } +} +impl CreateBoostResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBoostResponse"; +} +::buffa::impl_default_instance!(CreateBoostResponse); +impl ::buffa::MessageName for CreateBoostResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBoostResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBoostResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBoostResponse"; +} +impl ::buffa::Message for CreateBoostResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.boost.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.boost.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.fapshi_transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.fapshi_transaction_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.boost.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.boost.write_to(__cache, buf); + } + if !self.fapshi_transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.fapshi_transaction_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.boost.get_or_insert_default(), + buf, + ctx, + )?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.fapshi_transaction_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.boost = ::buffa::MessageField::none(); + self.fapshi_transaction_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateBoostResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateBoostResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateBoostResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_BOOST_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateBoostResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetBoostStatusRequest { + /// Field 1: `boost_id` + #[serde( + rename = "boostId", + alias = "boost_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub boost_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetBoostStatusRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetBoostStatusRequest") + .field("boost_id", &self.boost_id) + .finish() + } +} +impl GetBoostStatusRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBoostStatusRequest"; +} +::buffa::impl_default_instance!(GetBoostStatusRequest); +impl ::buffa::MessageName for GetBoostStatusRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetBoostStatusRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetBoostStatusRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBoostStatusRequest"; +} +impl ::buffa::Message for GetBoostStatusRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.boost_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.boost_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.boost_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.boost_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.boost_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.boost_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetBoostStatusRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetBoostStatusRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetBoostStatusRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_BOOST_STATUS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetBoostStatusRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetBoostStatusResponse { + /// Field 1: `boost` + #[serde( + rename = "boost", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub boost: ::buffa::MessageField>, + /// Field 2: `outcome` + #[serde( + rename = "outcome", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub outcome: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetBoostStatusResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetBoostStatusResponse") + .field("boost", &self.boost) + .field("outcome", &self.outcome) + .finish() + } +} +impl GetBoostStatusResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBoostStatusResponse"; +} +::buffa::impl_default_instance!(GetBoostStatusResponse); +impl ::buffa::MessageName for GetBoostStatusResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetBoostStatusResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetBoostStatusResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBoostStatusResponse"; +} +impl ::buffa::Message for GetBoostStatusResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.boost.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.boost.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.outcome.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.outcome.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.boost.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.boost.write_to(__cache, buf); + } + if self.outcome.is_set() { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + self.outcome.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.boost.get_or_insert_default(), + buf, + ctx, + )?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.outcome.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.boost = ::buffa::MessageField::none(); + self.outcome = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetBoostStatusResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetBoostStatusResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetBoostStatusResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_BOOST_STATUS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetBoostStatusResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct PaymentOutcome { + /// Field 1: `status` + #[serde( + rename = "status", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub status: ::buffa::alloc::string::String, + /// Field 2: `message` + #[serde( + rename = "message", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub message: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for PaymentOutcome { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("PaymentOutcome") + .field("status", &self.status) + .field("message", &self.message) + .finish() + } +} +impl PaymentOutcome { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.PaymentOutcome"; +} +::buffa::impl_default_instance!(PaymentOutcome); +impl ::buffa::MessageName for PaymentOutcome { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "PaymentOutcome"; + const FULL_NAME: &'static str = "bookbridge.v1.PaymentOutcome"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.PaymentOutcome"; +} +impl ::buffa::Message for PaymentOutcome { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.status.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.status) as u64; + } + if !self.message.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.message) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.status.is_empty() { + ::buffa::types::put_string_field(1u32, &self.status, buf); + } + if !self.message.is_empty() { + ::buffa::types::put_string_field(2u32, &self.message, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.status, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.message, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.status.clear(); + self.message.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for PaymentOutcome { + const PROTO_FQN: &'static str = "bookbridge.v1.PaymentOutcome"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for PaymentOutcome { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __PAYMENT_OUTCOME_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.PaymentOutcome", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateDonationRequest { + /// Field 1: `amount_fcfa` + #[serde( + rename = "amountFcfa", + alias = "amount_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub amount_fcfa: i64, + /// Field 2: `message` + #[serde( + rename = "message", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub message: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateDonationRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateDonationRequest") + .field("amount_fcfa", &self.amount_fcfa) + .field("message", &self.message) + .finish() + } +} +impl CreateDonationRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateDonationRequest"; +} +::buffa::impl_default_instance!(CreateDonationRequest); +impl ::buffa::MessageName for CreateDonationRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateDonationRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateDonationRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateDonationRequest"; +} +impl ::buffa::Message for CreateDonationRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.amount_fcfa != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + if !self.message.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.message) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(1u32, self.amount_fcfa, buf); + } + if !self.message.is_empty() { + ::buffa::types::put_string_field(2u32, &self.message, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.amount_fcfa = ::buffa::types::decode_int64(buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.message, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.amount_fcfa = 0i64; + self.message.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateDonationRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateDonationRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateDonationRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_DONATION_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateDonationRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Donation { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `amount_fcfa` + #[serde( + rename = "amountFcfa", + alias = "amount_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub amount_fcfa: i64, + /// Field 3: `message` + #[serde( + rename = "message", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub message: ::buffa::alloc::string::String, + /// Field 4: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Donation { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Donation") + .field("id", &self.id) + .field("amount_fcfa", &self.amount_fcfa) + .field("message", &self.message) + .field("created_at", &self.created_at) + .finish() + } +} +impl Donation { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Donation"; +} +::buffa::impl_default_instance!(Donation); +impl ::buffa::MessageName for Donation { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Donation"; + const FULL_NAME: &'static str = "bookbridge.v1.Donation"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Donation"; +} +impl ::buffa::Message for Donation { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if self.amount_fcfa != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + if !self.message.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.message) as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(2u32, self.amount_fcfa, buf); + } + if !self.message.is_empty() { + ::buffa::types::put_string_field(3u32, &self.message, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 4u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.amount_fcfa = ::buffa::types::decode_int64(buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.message, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.amount_fcfa = 0i64; + self.message.clear(); + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Donation { + const PROTO_FQN: &'static str = "bookbridge.v1.Donation"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Donation { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DONATION_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Donation", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateDonationResponse { + /// Field 1: `donation` + #[serde( + rename = "donation", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub donation: ::buffa::MessageField>, + /// Field 2: `fapshi_transaction_id` + #[serde( + rename = "fapshiTransactionId", + alias = "fapshi_transaction_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub fapshi_transaction_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateDonationResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateDonationResponse") + .field("donation", &self.donation) + .field("fapshi_transaction_id", &self.fapshi_transaction_id) + .finish() + } +} +impl CreateDonationResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateDonationResponse"; +} +::buffa::impl_default_instance!(CreateDonationResponse); +impl ::buffa::MessageName for CreateDonationResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateDonationResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateDonationResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateDonationResponse"; +} +impl ::buffa::Message for CreateDonationResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.donation.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.donation.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.fapshi_transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.fapshi_transaction_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.donation.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.donation.write_to(__cache, buf); + } + if !self.fapshi_transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.fapshi_transaction_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.donation.get_or_insert_default(), + buf, + ctx, + )?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.fapshi_transaction_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.donation = ::buffa::MessageField::none(); + self.fapshi_transaction_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateDonationResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateDonationResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateDonationResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_DONATION_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateDonationResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Maps to conversation_messages. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Message { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `conversation_id` + #[serde( + rename = "conversationId", + alias = "conversation_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub conversation_id: ::buffa::alloc::string::String, + /// Field 3: `user_id` + #[serde( + rename = "userId", + alias = "user_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub user_id: ::buffa::alloc::string::String, + /// Field 4: `content` + #[serde( + rename = "content", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub content: ::buffa::alloc::string::String, + /// Field 5: `attachment` + #[serde( + rename = "attachment", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub attachment: ::buffa::MessageField< + UploadAttachment, + ::buffa::Inline, + >, + /// Field 6: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Message { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Message") + .field("id", &self.id) + .field("conversation_id", &self.conversation_id) + .field("user_id", &self.user_id) + .field("content", &self.content) + .field("attachment", &self.attachment) + .field("created_at", &self.created_at) + .finish() + } +} +impl Message { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Message"; +} +::buffa::impl_default_instance!(Message); +impl ::buffa::MessageName for Message { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Message"; + const FULL_NAME: &'static str = "bookbridge.v1.Message"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Message"; +} +impl ::buffa::Message for Message { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.conversation_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.conversation_id) as u64; + } + if !self.user_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.user_id) as u64; + } + if !self.content.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.content) as u64; + } + if self.attachment.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.attachment.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.conversation_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.conversation_id, buf); + } + if !self.user_id.is_empty() { + ::buffa::types::put_string_field(3u32, &self.user_id, buf); + } + if !self.content.is_empty() { + ::buffa::types::put_string_field(4u32, &self.content, buf); + } + if self.attachment.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.attachment.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.conversation_id, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.user_id, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.content, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.attachment.get_or_insert_default(), + buf, + ctx, + )?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.conversation_id.clear(); + self.user_id.clear(); + self.content.clear(); + self.attachment = ::buffa::MessageField::none(); + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Message { + const PROTO_FQN: &'static str = "bookbridge.v1.Message"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Message { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __MESSAGE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Message", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct UploadAttachment { + /// Field 1: `upload_id` + #[serde( + rename = "uploadId", + alias = "upload_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub upload_id: ::buffa::alloc::string::String, + /// Field 2: `url` + #[serde( + rename = "url", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub url: ::buffa::alloc::string::String, + /// Field 3: `content_type` + #[serde( + rename = "contentType", + alias = "content_type", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub content_type: ::buffa::alloc::string::String, + /// Field 4: `file_name` + #[serde( + rename = "fileName", + alias = "file_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub file_name: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for UploadAttachment { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("UploadAttachment") + .field("upload_id", &self.upload_id) + .field("url", &self.url) + .field("content_type", &self.content_type) + .field("file_name", &self.file_name) + .finish() + } +} +impl UploadAttachment { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UploadAttachment"; +} +::buffa::impl_default_instance!(UploadAttachment); +impl ::buffa::MessageName for UploadAttachment { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UploadAttachment"; + const FULL_NAME: &'static str = "bookbridge.v1.UploadAttachment"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UploadAttachment"; +} +impl ::buffa::Message for UploadAttachment { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + if !self.url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.url) as u64; + } + if !self.content_type.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.content_type) as u64; + } + if !self.file_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.file_name) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + if !self.url.is_empty() { + ::buffa::types::put_string_field(2u32, &self.url, buf); + } + if !self.content_type.is_empty() { + ::buffa::types::put_string_field(3u32, &self.content_type, buf); + } + if !self.file_name.is_empty() { + ::buffa::types::put_string_field(4u32, &self.file_name, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.upload_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.url, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.content_type, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.file_name, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.upload_id.clear(); + self.url.clear(); + self.content_type.clear(); + self.file_name.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for UploadAttachment { + const PROTO_FQN: &'static str = "bookbridge.v1.UploadAttachment"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for UploadAttachment { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __UPLOAD_ATTACHMENT_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.UploadAttachment", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Conversation summary (conversations table + last message + unread count). +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Conversation { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + /// Field 3: `book` + #[serde( + rename = "book", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub book: ::buffa::MessageField>, + /// Field 4: `other_participant` + #[serde( + rename = "otherParticipant", + alias = "other_participant", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub other_participant: ::buffa::MessageField< + UserSummary, + ::buffa::Inline, + >, + /// Field 5: `last_message` + #[serde( + rename = "lastMessage", + alias = "last_message", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub last_message: ::buffa::alloc::string::String, + /// Field 6: `last_message_at` + #[serde( + rename = "lastMessageAt", + alias = "last_message_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub last_message_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 7: `unread_count` + #[serde( + rename = "unreadCount", + alias = "unread_count", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub unread_count: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Conversation { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Conversation") + .field("id", &self.id) + .field("book_id", &self.book_id) + .field("book", &self.book) + .field("other_participant", &self.other_participant) + .field("last_message", &self.last_message) + .field("last_message_at", &self.last_message_at) + .field("unread_count", &self.unread_count) + .finish() + } +} +impl Conversation { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Conversation"; +} +::buffa::impl_default_instance!(Conversation); +impl ::buffa::MessageName for Conversation { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Conversation"; + const FULL_NAME: &'static str = "bookbridge.v1.Conversation"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Conversation"; +} +impl ::buffa::Message for Conversation { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.other_participant.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.other_participant.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.last_message.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.last_message) as u64; + } + if self.last_message_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.last_message_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.unread_count != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.unread_count) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.book_id, buf); + } + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 3u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + if self.other_participant.is_set() { + ::buffa::types::put_len_delimited_header( + 4u32, + u64::from(__cache.consume_next()), + buf, + ); + self.other_participant.write_to(__cache, buf); + } + if !self.last_message.is_empty() { + ::buffa::types::put_string_field(5u32, &self.last_message, buf); + } + if self.last_message_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.last_message_at.write_to(__cache, buf); + } + if self.unread_count != 0i32 { + ::buffa::types::put_int32_field(7u32, self.unread_count, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.book.get_or_insert_default(), + buf, + ctx, + )?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.other_participant.get_or_insert_default(), + buf, + ctx, + )?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.last_message, buf)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.last_message_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.unread_count = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.book_id.clear(); + self.book = ::buffa::MessageField::none(); + self.other_participant = ::buffa::MessageField::none(); + self.last_message.clear(); + self.last_message_at = ::buffa::MessageField::none(); + self.unread_count = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Conversation { + const PROTO_FQN: &'static str = "bookbridge.v1.Conversation"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Conversation { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CONVERSATION_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Conversation", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Lightweight book info for conversation list rows. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct BookSummary { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `title` + #[serde( + rename = "title", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub title: ::buffa::alloc::string::String, + /// Field 3: `cover_url` + #[serde( + rename = "coverUrl", + alias = "cover_url", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub cover_url: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for BookSummary { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("BookSummary") + .field("id", &self.id) + .field("title", &self.title) + .field("cover_url", &self.cover_url) + .finish() + } +} +impl BookSummary { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookSummary"; +} +::buffa::impl_default_instance!(BookSummary); +impl ::buffa::MessageName for BookSummary { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "BookSummary"; + const FULL_NAME: &'static str = "bookbridge.v1.BookSummary"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookSummary"; +} +impl ::buffa::Message for BookSummary { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.title.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.cover_url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.cover_url) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.title.is_empty() { + ::buffa::types::put_string_field(2u32, &self.title, buf); + } + if !self.cover_url.is_empty() { + ::buffa::types::put_string_field(3u32, &self.cover_url, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.title, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.cover_url, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.title.clear(); + self.cover_url.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for BookSummary { + const PROTO_FQN: &'static str = "bookbridge.v1.BookSummary"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for BookSummary { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __BOOK_SUMMARY_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.BookSummary", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListConversationsRequest { + /// Field 1: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 2: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListConversationsRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListConversationsRequest") + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .finish() + } +} +impl ListConversationsRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListConversationsRequest"; +} +::buffa::impl_default_instance!(ListConversationsRequest); +impl ::buffa::MessageName for ListConversationsRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListConversationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListConversationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListConversationsRequest"; +} +impl ::buffa::Message for ListConversationsRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.page_token.clear(); + self.page_size = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListConversationsRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListConversationsRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListConversationsRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_CONVERSATIONS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListConversationsRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListConversationsResponse { + /// Field 1: `conversations` + #[serde( + rename = "conversations", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub conversations: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListConversationsResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListConversationsResponse") + .field("conversations", &self.conversations) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListConversationsResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListConversationsResponse"; +} +::buffa::impl_default_instance!(ListConversationsResponse); +impl ::buffa::MessageName for ListConversationsResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListConversationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListConversationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListConversationsResponse"; +} +impl ::buffa::Message for ListConversationsResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.conversations { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.conversations { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.conversations.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.conversations.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListConversationsResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListConversationsResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListConversationsResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_CONVERSATIONS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListConversationsResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetOrCreateConversationRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetOrCreateConversationRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetOrCreateConversationRequest") + .field("book_id", &self.book_id) + .finish() + } +} +impl GetOrCreateConversationRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetOrCreateConversationRequest"; +} +::buffa::impl_default_instance!(GetOrCreateConversationRequest); +impl ::buffa::MessageName for GetOrCreateConversationRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetOrCreateConversationRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetOrCreateConversationRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetOrCreateConversationRequest"; +} +impl ::buffa::Message for GetOrCreateConversationRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetOrCreateConversationRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetOrCreateConversationRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetOrCreateConversationRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_OR_CREATE_CONVERSATION_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetOrCreateConversationRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetOrCreateConversationResponse { + /// Field 1: `conversation` + #[serde( + rename = "conversation", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub conversation: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetOrCreateConversationResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetOrCreateConversationResponse") + .field("conversation", &self.conversation) + .finish() + } +} +impl GetOrCreateConversationResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetOrCreateConversationResponse"; +} +::buffa::impl_default_instance!(GetOrCreateConversationResponse); +impl ::buffa::MessageName for GetOrCreateConversationResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetOrCreateConversationResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetOrCreateConversationResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetOrCreateConversationResponse"; +} +impl ::buffa::Message for GetOrCreateConversationResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.conversation.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.conversation.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.conversation.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.conversation.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.conversation.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.conversation = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetOrCreateConversationResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetOrCreateConversationResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetOrCreateConversationResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_OR_CREATE_CONVERSATION_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetOrCreateConversationResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMessagesRequest { + /// Field 1: `conversation_id` + #[serde( + rename = "conversationId", + alias = "conversation_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub conversation_id: ::buffa::alloc::string::String, + /// Field 2: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 3: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMessagesRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMessagesRequest") + .field("conversation_id", &self.conversation_id) + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .finish() + } +} +impl ListMessagesRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMessagesRequest"; +} +::buffa::impl_default_instance!(ListMessagesRequest); +impl ::buffa::MessageName for ListMessagesRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMessagesRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMessagesRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMessagesRequest"; +} +impl ::buffa::Message for ListMessagesRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.conversation_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.conversation_id) as u64; + } + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.conversation_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.conversation_id, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(3u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.conversation_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.conversation_id.clear(); + self.page_token.clear(); + self.page_size = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMessagesRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMessagesRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMessagesRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MESSAGES_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMessagesRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMessagesResponse { + /// Field 1: `messages` + #[serde( + rename = "messages", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub messages: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMessagesResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMessagesResponse") + .field("messages", &self.messages) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListMessagesResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMessagesResponse"; +} +::buffa::impl_default_instance!(ListMessagesResponse); +impl ::buffa::MessageName for ListMessagesResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMessagesResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMessagesResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMessagesResponse"; +} +impl ::buffa::Message for ListMessagesResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.messages { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.messages { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.messages.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.messages.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMessagesResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMessagesResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMessagesResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MESSAGES_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMessagesResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SendMessageRequest { + /// Field 1: `conversation_id` + #[serde( + rename = "conversationId", + alias = "conversation_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub conversation_id: ::buffa::alloc::string::String, + /// Field 2: `content` + #[serde( + rename = "content", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub content: ::buffa::alloc::string::String, + /// Field 3: `attachment_upload_id` + #[serde( + rename = "attachmentUploadId", + alias = "attachment_upload_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub attachment_upload_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SendMessageRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SendMessageRequest") + .field("conversation_id", &self.conversation_id) + .field("content", &self.content) + .field("attachment_upload_id", &self.attachment_upload_id) + .finish() + } +} +impl SendMessageRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendMessageRequest"; +} +::buffa::impl_default_instance!(SendMessageRequest); +impl ::buffa::MessageName for SendMessageRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SendMessageRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SendMessageRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendMessageRequest"; +} +impl ::buffa::Message for SendMessageRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.conversation_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.conversation_id) as u64; + } + if !self.content.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.content) as u64; + } + if !self.attachment_upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.attachment_upload_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.conversation_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.conversation_id, buf); + } + if !self.content.is_empty() { + ::buffa::types::put_string_field(2u32, &self.content, buf); + } + if !self.attachment_upload_id.is_empty() { + ::buffa::types::put_string_field(3u32, &self.attachment_upload_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.conversation_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.content, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.attachment_upload_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.conversation_id.clear(); + self.content.clear(); + self.attachment_upload_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SendMessageRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.SendMessageRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SendMessageRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SEND_MESSAGE_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SendMessageRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct SendMessageResponse { + /// Field 1: `message` + #[serde( + rename = "message", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub message: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for SendMessageResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SendMessageResponse").field("message", &self.message).finish() + } +} +impl SendMessageResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendMessageResponse"; +} +::buffa::impl_default_instance!(SendMessageResponse); +impl ::buffa::MessageName for SendMessageResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SendMessageResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SendMessageResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendMessageResponse"; +} +impl ::buffa::Message for SendMessageResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.message.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.message.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.message.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.message.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.message.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.message = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for SendMessageResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.SendMessageResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for SendMessageResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SEND_MESSAGE_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.SendMessageResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct MarkMessagesReadRequest { + /// Field 1: `conversation_id` + #[serde( + rename = "conversationId", + alias = "conversation_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub conversation_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for MarkMessagesReadRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MarkMessagesReadRequest") + .field("conversation_id", &self.conversation_id) + .finish() + } +} +impl MarkMessagesReadRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkMessagesReadRequest"; +} +::buffa::impl_default_instance!(MarkMessagesReadRequest); +impl ::buffa::MessageName for MarkMessagesReadRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkMessagesReadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkMessagesReadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkMessagesReadRequest"; +} +impl ::buffa::Message for MarkMessagesReadRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.conversation_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.conversation_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.conversation_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.conversation_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.conversation_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.conversation_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for MarkMessagesReadRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.MarkMessagesReadRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for MarkMessagesReadRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __MARK_MESSAGES_READ_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.MarkMessagesReadRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct MarkMessagesReadResponse { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for MarkMessagesReadResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MarkMessagesReadResponse").finish() + } +} +impl MarkMessagesReadResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkMessagesReadResponse"; +} +::buffa::impl_default_instance!(MarkMessagesReadResponse); +impl ::buffa::MessageName for MarkMessagesReadResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkMessagesReadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkMessagesReadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkMessagesReadResponse"; +} +impl ::buffa::Message for MarkMessagesReadResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for MarkMessagesReadResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.MarkMessagesReadResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for MarkMessagesReadResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __MARK_MESSAGES_READ_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.MarkMessagesReadResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Server-streamed conversation events for real-time updates. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct StreamConversationsRequest { + /// Client cursor: only events for changes after this timestamp are sent. + /// + /// Field 1: `since` + #[serde( + rename = "since", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub since: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for StreamConversationsRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("StreamConversationsRequest").field("since", &self.since).finish() + } +} +impl StreamConversationsRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamConversationsRequest"; +} +::buffa::impl_default_instance!(StreamConversationsRequest); +impl ::buffa::MessageName for StreamConversationsRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "StreamConversationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.StreamConversationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamConversationsRequest"; +} +impl ::buffa::Message for StreamConversationsRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.since.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.since.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.since.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.since.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.since.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.since = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for StreamConversationsRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.StreamConversationsRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for StreamConversationsRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __STREAM_CONVERSATIONS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.StreamConversationsRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize)] +#[serde(default)] +pub struct StreamConversationsResponse { + #[serde(flatten)] + pub event: ::core::option::Option< + __buffa::oneof::stream_conversations_response::Event, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for StreamConversationsResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("StreamConversationsResponse") + .field("event", &self.event) + .finish() + } +} +impl StreamConversationsResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamConversationsResponse"; +} +::buffa::impl_default_instance!(StreamConversationsResponse); +impl ::buffa::MessageName for StreamConversationsResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "StreamConversationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.StreamConversationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamConversationsResponse"; +} +impl ::buffa::Message for StreamConversationsResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if let ::core::option::Option::Some(ref v) = self.event { + match v { + __buffa::oneof::stream_conversations_response::Event::Upserted(x) => { + let __slot = __cache.reserve(); + let inner = x.compute_size(__cache); + __cache.set(__slot, inner); + size + += 1u64 + ::buffa::encoding::varint_len(inner as u64) as u64 + + inner as u64; + } + __buffa::oneof::stream_conversations_response::Event::MessageCreated( + x, + ) => { + let __slot = __cache.reserve(); + let inner = x.compute_size(__cache); + __cache.set(__slot, inner); + size + += 1u64 + ::buffa::encoding::varint_len(inner as u64) as u64 + + inner as u64; + } + } + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let ::core::option::Option::Some(ref v) = self.event { + match v { + __buffa::oneof::stream_conversations_response::Event::Upserted(x) => { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + x.write_to(__cache, buf); + } + __buffa::oneof::stream_conversations_response::Event::MessageCreated( + x, + ) => { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + x.write_to(__cache, buf); + } + } + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + if let ::core::option::Option::Some( + __buffa::oneof::stream_conversations_response::Event::Upserted( + ref mut existing, + ), + ) = self.event + { + ::buffa::Message::merge_length_delimited(&mut **existing, buf, ctx)?; + } else { + let mut val = ::core::default::Default::default(); + ::buffa::Message::merge_length_delimited(&mut val, buf, ctx)?; + self.event = ::core::option::Option::Some( + __buffa::oneof::stream_conversations_response::Event::Upserted( + ::buffa::alloc::boxed::Box::new(val), + ), + ); + } + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + if let ::core::option::Option::Some( + __buffa::oneof::stream_conversations_response::Event::MessageCreated( + ref mut existing, + ), + ) = self.event + { + ::buffa::Message::merge_length_delimited(&mut **existing, buf, ctx)?; + } else { + let mut val = ::core::default::Default::default(); + ::buffa::Message::merge_length_delimited(&mut val, buf, ctx)?; + self.event = ::core::option::Option::Some( + __buffa::oneof::stream_conversations_response::Event::MessageCreated( + ::buffa::alloc::boxed::Box::new(val), + ), + ); + } + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.event = ::core::option::Option::None; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for StreamConversationsResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.StreamConversationsResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl<'de> ::serde::Deserialize<'de> for StreamConversationsResponse { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl<'de> ::serde::de::Visitor<'de> for _V { + type Value = StreamConversationsResponse; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str("struct StreamConversationsResponse") + } + #[allow(clippy::field_reassign_with_default)] + fn visit_map>( + self, + mut map: A, + ) -> ::core::result::Result { + let mut __oneof_event: ::core::option::Option< + __buffa::oneof::stream_conversations_response::Event, + > = None; + while let Some(key) = map.next_key::<::buffa::alloc::string::String>()? { + match key.as_str() { + "upserted" => { + let v: ::core::option::Option = map + .next_value_seed( + ::buffa::json_helpers::NullableDeserializeSeed( + ::buffa::json_helpers::DefaultDeserializeSeed::< + Conversation, + >::new(), + ), + )?; + if let Some(v) = v { + if __oneof_event.is_some() { + return Err( + ::serde::de::Error::custom( + "multiple oneof fields set for 'event'", + ), + ); + } + __oneof_event = Some( + __buffa::oneof::stream_conversations_response::Event::Upserted( + ::buffa::alloc::boxed::Box::new(v), + ), + ); + } + } + "messageCreated" | "message_created" => { + let v: ::core::option::Option = map + .next_value_seed( + ::buffa::json_helpers::NullableDeserializeSeed( + ::buffa::json_helpers::DefaultDeserializeSeed::< + Message, + >::new(), + ), + )?; + if let Some(v) = v { + if __oneof_event.is_some() { + return Err( + ::serde::de::Error::custom( + "multiple oneof fields set for 'event'", + ), + ); + } + __oneof_event = Some( + __buffa::oneof::stream_conversations_response::Event::MessageCreated( + ::buffa::alloc::boxed::Box::new(v), + ), + ); + } + } + _ => { + map.next_value::<::serde::de::IgnoredAny>()?; + } + } + } + let mut __r = ::default(); + __r.event = __oneof_event; + Ok(__r) + } + } + d.deserialize_map(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for StreamConversationsResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __STREAM_CONVERSATIONS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.StreamConversationsResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +pub mod stream_conversations_response { + #[allow(unused_imports)] + use super::*; + #[doc(inline)] + pub use super::__buffa::oneof::stream_conversations_response::Event; + #[doc(inline)] + pub use super::__buffa::view::oneof::stream_conversations_response::Event as EventView; +} +/// Maps to the meetup_locations table. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct MeetupLocation { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `name` + #[serde( + rename = "name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub name: ::buffa::alloc::string::String, + /// Field 3: `description` + #[serde( + rename = "description", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub description: ::buffa::alloc::string::String, + /// Field 4: `verified` + #[serde( + rename = "verified", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub verified: bool, + /// Field 5: `location` + #[serde( + rename = "location", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub location: ::buffa::MessageField>, + /// Field 6: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for MeetupLocation { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MeetupLocation") + .field("id", &self.id) + .field("name", &self.name) + .field("description", &self.description) + .field("verified", &self.verified) + .field("location", &self.location) + .field("created_at", &self.created_at) + .finish() + } +} +impl MeetupLocation { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MeetupLocation"; +} +::buffa::impl_default_instance!(MeetupLocation); +impl ::buffa::MessageName for MeetupLocation { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MeetupLocation"; + const FULL_NAME: &'static str = "bookbridge.v1.MeetupLocation"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MeetupLocation"; +} +impl ::buffa::Message for MeetupLocation { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.name) as u64; + } + if !self.description.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.description) as u64; + } + if self.verified { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.name.is_empty() { + ::buffa::types::put_string_field(2u32, &self.name, buf); + } + if !self.description.is_empty() { + ::buffa::types::put_string_field(3u32, &self.description, buf); + } + if self.verified { + ::buffa::types::put_bool_field(4u32, self.verified, buf); + } + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.name, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.description, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.verified = ::buffa::types::decode_bool(buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.location.get_or_insert_default(), + buf, + ctx, + )?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.name.clear(); + self.description.clear(); + self.verified = false; + self.location = ::buffa::MessageField::none(); + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for MeetupLocation { + const PROTO_FQN: &'static str = "bookbridge.v1.MeetupLocation"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for MeetupLocation { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __MEETUP_LOCATION_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.MeetupLocation", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMeetupLocationsRequest { + /// When set, only return locations within radius of the center. + /// + /// Field 1: `center` + #[serde( + rename = "center", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub center: ::buffa::MessageField>, + /// Field 2: `radius_km` + #[serde( + rename = "radiusKm", + alias = "radius_km", + with = "::buffa::json_helpers::double", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_f64" + )] + pub radius_km: f64, + /// Field 3: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 4: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMeetupLocationsRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMeetupLocationsRequest") + .field("center", &self.center) + .field("radius_km", &self.radius_km) + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .finish() + } +} +impl ListMeetupLocationsRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMeetupLocationsRequest"; +} +::buffa::impl_default_instance!(ListMeetupLocationsRequest); +impl ::buffa::MessageName for ListMeetupLocationsRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMeetupLocationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMeetupLocationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMeetupLocationsRequest"; +} +impl ::buffa::Message for ListMeetupLocationsRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.center.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.center.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.radius_km.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.center.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.center.write_to(__cache, buf); + } + if self.radius_km.to_bits() != 0u64 { + ::buffa::types::put_double_field(2u32, self.radius_km, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(3u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(4u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.center.get_or_insert_default(), + buf, + ctx, + )?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + self.radius_km = ::buffa::types::decode_double(buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.center = ::buffa::MessageField::none(); + self.radius_km = 0f64; + self.page_token.clear(); + self.page_size = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMeetupLocationsRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMeetupLocationsRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMeetupLocationsRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MEETUP_LOCATIONS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMeetupLocationsRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMeetupLocationsResponse { + /// Field 1: `locations` + #[serde( + rename = "locations", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub locations: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMeetupLocationsResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMeetupLocationsResponse") + .field("locations", &self.locations) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListMeetupLocationsResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMeetupLocationsResponse"; +} +::buffa::impl_default_instance!(ListMeetupLocationsResponse); +impl ::buffa::MessageName for ListMeetupLocationsResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMeetupLocationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMeetupLocationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMeetupLocationsResponse"; +} +impl ::buffa::Message for ListMeetupLocationsResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.locations { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.locations { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.locations.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.locations.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMeetupLocationsResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMeetupLocationsResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMeetupLocationsResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MEETUP_LOCATIONS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMeetupLocationsResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetMeetupLocationRequest { + /// Field 1: `location_id` + #[serde( + rename = "locationId", + alias = "location_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub location_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetMeetupLocationRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetMeetupLocationRequest") + .field("location_id", &self.location_id) + .finish() + } +} +impl GetMeetupLocationRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetMeetupLocationRequest"; +} +::buffa::impl_default_instance!(GetMeetupLocationRequest); +impl ::buffa::MessageName for GetMeetupLocationRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetMeetupLocationRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetMeetupLocationRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetMeetupLocationRequest"; +} +impl ::buffa::Message for GetMeetupLocationRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.location_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.location_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.location_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.location_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.location_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.location_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetMeetupLocationRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetMeetupLocationRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetMeetupLocationRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_MEETUP_LOCATION_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetMeetupLocationRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetMeetupLocationResponse { + /// Field 1: `location` + #[serde( + rename = "location", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub location: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetMeetupLocationResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetMeetupLocationResponse") + .field("location", &self.location) + .finish() + } +} +impl GetMeetupLocationResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetMeetupLocationResponse"; +} +::buffa::impl_default_instance!(GetMeetupLocationResponse); +impl ::buffa::MessageName for GetMeetupLocationResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetMeetupLocationResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetMeetupLocationResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetMeetupLocationResponse"; +} +impl ::buffa::Message for GetMeetupLocationResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.location.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.location = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetMeetupLocationResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetMeetupLocationResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetMeetupLocationResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_MEETUP_LOCATION_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetMeetupLocationResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Maps to notifications joined with notification_bodies / template translations. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Notification { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `title` + #[serde( + rename = "title", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub title: ::buffa::alloc::string::String, + /// Field 3: `body` + #[serde( + rename = "body", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub body: ::buffa::alloc::string::String, + /// Field 4: `type` + #[serde( + rename = "type", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub r#type: ::buffa::alloc::string::String, + /// Field 5: `data` + #[serde( + rename = "data", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub data: ::buffa::MessageField< + ::buffa_types::google::protobuf::Struct, + ::buffa::Inline<::buffa_types::google::protobuf::Struct>, + >, + /// Field 6: `read_at` + #[serde( + rename = "readAt", + alias = "read_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub read_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 7: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Notification { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Notification") + .field("id", &self.id) + .field("title", &self.title) + .field("body", &self.body) + .field("type", &self.r#type) + .field("data", &self.data) + .field("read_at", &self.read_at) + .field("created_at", &self.created_at) + .finish() + } +} +impl Notification { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Notification"; +} +::buffa::impl_default_instance!(Notification); +impl ::buffa::MessageName for Notification { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Notification"; + const FULL_NAME: &'static str = "bookbridge.v1.Notification"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Notification"; +} +impl ::buffa::Message for Notification { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.title.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.body.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.body) as u64; + } + if !self.r#type.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.r#type) as u64; + } + if self.data.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.data.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.read_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.read_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.title.is_empty() { + ::buffa::types::put_string_field(2u32, &self.title, buf); + } + if !self.body.is_empty() { + ::buffa::types::put_string_field(3u32, &self.body, buf); + } + if !self.r#type.is_empty() { + ::buffa::types::put_string_field(4u32, &self.r#type, buf); + } + if self.data.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.data.write_to(__cache, buf); + } + if self.read_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.read_at.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 7u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.title, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.body, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.r#type, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.data.get_or_insert_default(), + buf, + ctx, + )?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.read_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.title.clear(); + self.body.clear(); + self.r#type.clear(); + self.data = ::buffa::MessageField::none(); + self.read_at = ::buffa::MessageField::none(); + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Notification { + const PROTO_FQN: &'static str = "bookbridge.v1.Notification"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Notification { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __NOTIFICATION_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Notification", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListNotificationsRequest { + /// Field 1: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 2: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + /// Field 3: `unread_only` + #[serde( + rename = "unreadOnly", + alias = "unread_only", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub unread_only: bool, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListNotificationsRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListNotificationsRequest") + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .field("unread_only", &self.unread_only) + .finish() + } +} +impl ListNotificationsRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListNotificationsRequest"; +} +::buffa::impl_default_instance!(ListNotificationsRequest); +impl ::buffa::MessageName for ListNotificationsRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListNotificationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListNotificationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListNotificationsRequest"; +} +impl ::buffa::Message for ListNotificationsRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + if self.unread_only { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + if self.unread_only { + ::buffa::types::put_bool_field(3u32, self.unread_only, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.unread_only = ::buffa::types::decode_bool(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.page_token.clear(); + self.page_size = 0i32; + self.unread_only = false; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListNotificationsRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListNotificationsRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListNotificationsRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_NOTIFICATIONS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListNotificationsRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListNotificationsResponse { + /// Field 1: `notifications` + #[serde( + rename = "notifications", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub notifications: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListNotificationsResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListNotificationsResponse") + .field("notifications", &self.notifications) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListNotificationsResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListNotificationsResponse"; +} +::buffa::impl_default_instance!(ListNotificationsResponse); +impl ::buffa::MessageName for ListNotificationsResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListNotificationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListNotificationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListNotificationsResponse"; +} +impl ::buffa::Message for ListNotificationsResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.notifications { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.notifications { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.notifications.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.notifications.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListNotificationsResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListNotificationsResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListNotificationsResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_NOTIFICATIONS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListNotificationsResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct MarkNotificationReadRequest { + /// Field 1: `notification_id` + #[serde( + rename = "notificationId", + alias = "notification_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub notification_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for MarkNotificationReadRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MarkNotificationReadRequest") + .field("notification_id", &self.notification_id) + .finish() + } +} +impl MarkNotificationReadRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkNotificationReadRequest"; +} +::buffa::impl_default_instance!(MarkNotificationReadRequest); +impl ::buffa::MessageName for MarkNotificationReadRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkNotificationReadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkNotificationReadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkNotificationReadRequest"; +} +impl ::buffa::Message for MarkNotificationReadRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.notification_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.notification_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.notification_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.notification_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.notification_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.notification_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for MarkNotificationReadRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.MarkNotificationReadRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for MarkNotificationReadRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __MARK_NOTIFICATION_READ_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.MarkNotificationReadRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct MarkNotificationReadResponse { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for MarkNotificationReadResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MarkNotificationReadResponse").finish() + } +} +impl MarkNotificationReadResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkNotificationReadResponse"; +} +::buffa::impl_default_instance!(MarkNotificationReadResponse); +impl ::buffa::MessageName for MarkNotificationReadResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkNotificationReadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkNotificationReadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkNotificationReadResponse"; +} +impl ::buffa::Message for MarkNotificationReadResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for MarkNotificationReadResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.MarkNotificationReadResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for MarkNotificationReadResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __MARK_NOTIFICATION_READ_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.MarkNotificationReadResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct MarkAllNotificationsReadRequest { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for MarkAllNotificationsReadRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MarkAllNotificationsReadRequest").finish() + } +} +impl MarkAllNotificationsReadRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkAllNotificationsReadRequest"; +} +::buffa::impl_default_instance!(MarkAllNotificationsReadRequest); +impl ::buffa::MessageName for MarkAllNotificationsReadRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkAllNotificationsReadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkAllNotificationsReadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkAllNotificationsReadRequest"; +} +impl ::buffa::Message for MarkAllNotificationsReadRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for MarkAllNotificationsReadRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.MarkAllNotificationsReadRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for MarkAllNotificationsReadRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __MARK_ALL_NOTIFICATIONS_READ_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.MarkAllNotificationsReadRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct MarkAllNotificationsReadResponse { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for MarkAllNotificationsReadResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("MarkAllNotificationsReadResponse").finish() + } +} +impl MarkAllNotificationsReadResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkAllNotificationsReadResponse"; +} +::buffa::impl_default_instance!(MarkAllNotificationsReadResponse); +impl ::buffa::MessageName for MarkAllNotificationsReadResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkAllNotificationsReadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkAllNotificationsReadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkAllNotificationsReadResponse"; +} +impl ::buffa::Message for MarkAllNotificationsReadResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for MarkAllNotificationsReadResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.MarkAllNotificationsReadResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for MarkAllNotificationsReadResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __MARK_ALL_NOTIFICATIONS_READ_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.MarkAllNotificationsReadResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Server-streamed notifications for real-time updates. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct StreamNotificationsRequest { + /// Field 1: `since` + #[serde( + rename = "since", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub since: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for StreamNotificationsRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("StreamNotificationsRequest").field("since", &self.since).finish() + } +} +impl StreamNotificationsRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamNotificationsRequest"; +} +::buffa::impl_default_instance!(StreamNotificationsRequest); +impl ::buffa::MessageName for StreamNotificationsRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "StreamNotificationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.StreamNotificationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamNotificationsRequest"; +} +impl ::buffa::Message for StreamNotificationsRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.since.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.since.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.since.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.since.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.since.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.since = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for StreamNotificationsRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.StreamNotificationsRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for StreamNotificationsRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __STREAM_NOTIFICATIONS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.StreamNotificationsRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct StreamNotificationsResponse { + /// Field 1: `notification` + #[serde( + rename = "notification", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub notification: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for StreamNotificationsResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("StreamNotificationsResponse") + .field("notification", &self.notification) + .finish() + } +} +impl StreamNotificationsResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamNotificationsResponse"; +} +::buffa::impl_default_instance!(StreamNotificationsResponse); +impl ::buffa::MessageName for StreamNotificationsResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "StreamNotificationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.StreamNotificationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamNotificationsResponse"; +} +impl ::buffa::Message for StreamNotificationsResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.notification.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.notification.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.notification.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.notification.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.notification.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.notification = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for StreamNotificationsResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.StreamNotificationsResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for StreamNotificationsResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __STREAM_NOTIFICATIONS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.StreamNotificationsResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Payment methods supported by the platform (Fapshi today). +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(i32)] +pub enum PaymentMethod { + PAYMENT_METHOD_UNSPECIFIED = 0i32, + PAYMENT_METHOD_FAPSHI = 1i32, +} +impl PaymentMethod { + ///Idiomatic alias for [`Self::PAYMENT_METHOD_UNSPECIFIED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Unspecified: Self = Self::PAYMENT_METHOD_UNSPECIFIED; + ///Idiomatic alias for [`Self::PAYMENT_METHOD_FAPSHI`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Fapshi: Self = Self::PAYMENT_METHOD_FAPSHI; +} +impl ::core::default::Default for PaymentMethod { + fn default() -> Self { + Self::PAYMENT_METHOD_UNSPECIFIED + } +} +impl ::serde::Serialize for PaymentMethod { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + s.serialize_str(::buffa::Enumeration::proto_name(self)) + } +} +impl<'de> ::serde::Deserialize<'de> for PaymentMethod { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl ::serde::de::Visitor<'_> for _V { + type Value = PaymentMethod; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str( + concat!("a string, integer, or null for ", stringify!(PaymentMethod)), + ) + } + fn visit_str( + self, + v: &str, + ) -> ::core::result::Result { + ::from_proto_name(v) + .ok_or_else(|| { ::serde::de::Error::unknown_variant(v, &[]) }) + } + fn visit_i64( + self, + v: i64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_u64( + self, + v: u64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_unit( + self, + ) -> ::core::result::Result { + ::core::result::Result::Ok(::core::default::Default::default()) + } + } + d.deserialize_any(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for PaymentMethod { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +impl ::buffa::Enumeration for PaymentMethod { + fn from_i32(value: i32) -> ::core::option::Option { + match value { + 0i32 => ::core::option::Option::Some(Self::PAYMENT_METHOD_UNSPECIFIED), + 1i32 => ::core::option::Option::Some(Self::PAYMENT_METHOD_FAPSHI), + _ => ::core::option::Option::None, + } + } + fn to_i32(&self) -> i32 { + *self as i32 + } + fn proto_name(&self) -> &'static str { + match self { + Self::PAYMENT_METHOD_UNSPECIFIED => "PAYMENT_METHOD_UNSPECIFIED", + Self::PAYMENT_METHOD_FAPSHI => "PAYMENT_METHOD_FAPSHI", + } + } + fn from_proto_name(name: &str) -> ::core::option::Option { + match name { + "PAYMENT_METHOD_UNSPECIFIED" => { + ::core::option::Option::Some(Self::PAYMENT_METHOD_UNSPECIFIED) + } + "PAYMENT_METHOD_FAPSHI" => { + ::core::option::Option::Some(Self::PAYMENT_METHOD_FAPSHI) + } + _ => ::core::option::Option::None, + } + } + fn values() -> &'static [Self] { + &[Self::PAYMENT_METHOD_UNSPECIFIED, Self::PAYMENT_METHOD_FAPSHI] + } +} +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(i32)] +pub enum PaymentStatus { + PAYMENT_STATUS_UNSPECIFIED = 0i32, + PAYMENT_STATUS_PENDING = 1i32, + PAYMENT_STATUS_COMPLETED = 2i32, + PAYMENT_STATUS_FAILED = 3i32, +} +impl PaymentStatus { + ///Idiomatic alias for [`Self::PAYMENT_STATUS_UNSPECIFIED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Unspecified: Self = Self::PAYMENT_STATUS_UNSPECIFIED; + ///Idiomatic alias for [`Self::PAYMENT_STATUS_PENDING`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Pending: Self = Self::PAYMENT_STATUS_PENDING; + ///Idiomatic alias for [`Self::PAYMENT_STATUS_COMPLETED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Completed: Self = Self::PAYMENT_STATUS_COMPLETED; + ///Idiomatic alias for [`Self::PAYMENT_STATUS_FAILED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Failed: Self = Self::PAYMENT_STATUS_FAILED; +} +impl ::core::default::Default for PaymentStatus { + fn default() -> Self { + Self::PAYMENT_STATUS_UNSPECIFIED + } +} +impl ::serde::Serialize for PaymentStatus { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + s.serialize_str(::buffa::Enumeration::proto_name(self)) + } +} +impl<'de> ::serde::Deserialize<'de> for PaymentStatus { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl ::serde::de::Visitor<'_> for _V { + type Value = PaymentStatus; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str( + concat!("a string, integer, or null for ", stringify!(PaymentStatus)), + ) + } + fn visit_str( + self, + v: &str, + ) -> ::core::result::Result { + ::from_proto_name(v) + .ok_or_else(|| { ::serde::de::Error::unknown_variant(v, &[]) }) + } + fn visit_i64( + self, + v: i64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_u64( + self, + v: u64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_unit( + self, + ) -> ::core::result::Result { + ::core::result::Result::Ok(::core::default::Default::default()) + } + } + d.deserialize_any(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for PaymentStatus { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +impl ::buffa::Enumeration for PaymentStatus { + fn from_i32(value: i32) -> ::core::option::Option { + match value { + 0i32 => ::core::option::Option::Some(Self::PAYMENT_STATUS_UNSPECIFIED), + 1i32 => ::core::option::Option::Some(Self::PAYMENT_STATUS_PENDING), + 2i32 => ::core::option::Option::Some(Self::PAYMENT_STATUS_COMPLETED), + 3i32 => ::core::option::Option::Some(Self::PAYMENT_STATUS_FAILED), + _ => ::core::option::Option::None, + } + } + fn to_i32(&self) -> i32 { + *self as i32 + } + fn proto_name(&self) -> &'static str { + match self { + Self::PAYMENT_STATUS_UNSPECIFIED => "PAYMENT_STATUS_UNSPECIFIED", + Self::PAYMENT_STATUS_PENDING => "PAYMENT_STATUS_PENDING", + Self::PAYMENT_STATUS_COMPLETED => "PAYMENT_STATUS_COMPLETED", + Self::PAYMENT_STATUS_FAILED => "PAYMENT_STATUS_FAILED", + } + } + fn from_proto_name(name: &str) -> ::core::option::Option { + match name { + "PAYMENT_STATUS_UNSPECIFIED" => { + ::core::option::Option::Some(Self::PAYMENT_STATUS_UNSPECIFIED) + } + "PAYMENT_STATUS_PENDING" => { + ::core::option::Option::Some(Self::PAYMENT_STATUS_PENDING) + } + "PAYMENT_STATUS_COMPLETED" => { + ::core::option::Option::Some(Self::PAYMENT_STATUS_COMPLETED) + } + "PAYMENT_STATUS_FAILED" => { + ::core::option::Option::Some(Self::PAYMENT_STATUS_FAILED) + } + _ => ::core::option::Option::None, + } + } + fn values() -> &'static [Self] { + &[ + Self::PAYMENT_STATUS_UNSPECIFIED, + Self::PAYMENT_STATUS_PENDING, + Self::PAYMENT_STATUS_COMPLETED, + Self::PAYMENT_STATUS_FAILED, + ] + } +} +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(i32)] +pub enum TransactionStatus { + TRANSACTION_STATUS_UNSPECIFIED = 0i32, + TRANSACTION_STATUS_HELD = 1i32, + TRANSACTION_STATUS_RELEASED = 2i32, + TRANSACTION_STATUS_REFUNDED = 3i32, + TRANSACTION_STATUS_DISPUTED = 4i32, +} +impl TransactionStatus { + ///Idiomatic alias for [`Self::TRANSACTION_STATUS_UNSPECIFIED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Unspecified: Self = Self::TRANSACTION_STATUS_UNSPECIFIED; + ///Idiomatic alias for [`Self::TRANSACTION_STATUS_HELD`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Held: Self = Self::TRANSACTION_STATUS_HELD; + ///Idiomatic alias for [`Self::TRANSACTION_STATUS_RELEASED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Released: Self = Self::TRANSACTION_STATUS_RELEASED; + ///Idiomatic alias for [`Self::TRANSACTION_STATUS_REFUNDED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Refunded: Self = Self::TRANSACTION_STATUS_REFUNDED; + ///Idiomatic alias for [`Self::TRANSACTION_STATUS_DISPUTED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Disputed: Self = Self::TRANSACTION_STATUS_DISPUTED; +} +impl ::core::default::Default for TransactionStatus { + fn default() -> Self { + Self::TRANSACTION_STATUS_UNSPECIFIED + } +} +impl ::serde::Serialize for TransactionStatus { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + s.serialize_str(::buffa::Enumeration::proto_name(self)) + } +} +impl<'de> ::serde::Deserialize<'de> for TransactionStatus { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl ::serde::de::Visitor<'_> for _V { + type Value = TransactionStatus; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str( + concat!( + "a string, integer, or null for ", stringify!(TransactionStatus) + ), + ) + } + fn visit_str( + self, + v: &str, + ) -> ::core::result::Result { + ::from_proto_name(v) + .ok_or_else(|| { ::serde::de::Error::unknown_variant(v, &[]) }) + } + fn visit_i64( + self, + v: i64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_u64( + self, + v: u64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_unit( + self, + ) -> ::core::result::Result { + ::core::result::Result::Ok(::core::default::Default::default()) + } + } + d.deserialize_any(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for TransactionStatus { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +impl ::buffa::Enumeration for TransactionStatus { + fn from_i32(value: i32) -> ::core::option::Option { + match value { + 0i32 => ::core::option::Option::Some(Self::TRANSACTION_STATUS_UNSPECIFIED), + 1i32 => ::core::option::Option::Some(Self::TRANSACTION_STATUS_HELD), + 2i32 => ::core::option::Option::Some(Self::TRANSACTION_STATUS_RELEASED), + 3i32 => ::core::option::Option::Some(Self::TRANSACTION_STATUS_REFUNDED), + 4i32 => ::core::option::Option::Some(Self::TRANSACTION_STATUS_DISPUTED), + _ => ::core::option::Option::None, + } + } + fn to_i32(&self) -> i32 { + *self as i32 + } + fn proto_name(&self) -> &'static str { + match self { + Self::TRANSACTION_STATUS_UNSPECIFIED => "TRANSACTION_STATUS_UNSPECIFIED", + Self::TRANSACTION_STATUS_HELD => "TRANSACTION_STATUS_HELD", + Self::TRANSACTION_STATUS_RELEASED => "TRANSACTION_STATUS_RELEASED", + Self::TRANSACTION_STATUS_REFUNDED => "TRANSACTION_STATUS_REFUNDED", + Self::TRANSACTION_STATUS_DISPUTED => "TRANSACTION_STATUS_DISPUTED", + } + } + fn from_proto_name(name: &str) -> ::core::option::Option { + match name { + "TRANSACTION_STATUS_UNSPECIFIED" => { + ::core::option::Option::Some(Self::TRANSACTION_STATUS_UNSPECIFIED) + } + "TRANSACTION_STATUS_HELD" => { + ::core::option::Option::Some(Self::TRANSACTION_STATUS_HELD) + } + "TRANSACTION_STATUS_RELEASED" => { + ::core::option::Option::Some(Self::TRANSACTION_STATUS_RELEASED) + } + "TRANSACTION_STATUS_REFUNDED" => { + ::core::option::Option::Some(Self::TRANSACTION_STATUS_REFUNDED) + } + "TRANSACTION_STATUS_DISPUTED" => { + ::core::option::Option::Some(Self::TRANSACTION_STATUS_DISPUTED) + } + _ => ::core::option::Option::None, + } + } + fn values() -> &'static [Self] { + &[ + Self::TRANSACTION_STATUS_UNSPECIFIED, + Self::TRANSACTION_STATUS_HELD, + Self::TRANSACTION_STATUS_RELEASED, + Self::TRANSACTION_STATUS_REFUNDED, + Self::TRANSACTION_STATUS_DISPUTED, + ] + } +} +/// What the payment is for (maps to payment_type enum in the schema). +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(i32)] +pub enum PaymentPurpose { + PAYMENT_PURPOSE_UNSPECIFIED = 0i32, + PAYMENT_PURPOSE_BOOK = 1i32, + PAYMENT_PURPOSE_DONATION = 2i32, + PAYMENT_PURPOSE_BOOST = 3i32, +} +impl PaymentPurpose { + ///Idiomatic alias for [`Self::PAYMENT_PURPOSE_UNSPECIFIED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Unspecified: Self = Self::PAYMENT_PURPOSE_UNSPECIFIED; + ///Idiomatic alias for [`Self::PAYMENT_PURPOSE_BOOK`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Book: Self = Self::PAYMENT_PURPOSE_BOOK; + ///Idiomatic alias for [`Self::PAYMENT_PURPOSE_DONATION`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Donation: Self = Self::PAYMENT_PURPOSE_DONATION; + ///Idiomatic alias for [`Self::PAYMENT_PURPOSE_BOOST`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Boost: Self = Self::PAYMENT_PURPOSE_BOOST; +} +impl ::core::default::Default for PaymentPurpose { + fn default() -> Self { + Self::PAYMENT_PURPOSE_UNSPECIFIED + } +} +impl ::serde::Serialize for PaymentPurpose { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + s.serialize_str(::buffa::Enumeration::proto_name(self)) + } +} +impl<'de> ::serde::Deserialize<'de> for PaymentPurpose { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl ::serde::de::Visitor<'_> for _V { + type Value = PaymentPurpose; + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.write_str( + concat!( + "a string, integer, or null for ", stringify!(PaymentPurpose) + ), + ) + } + fn visit_str( + self, + v: &str, + ) -> ::core::result::Result { + ::from_proto_name(v) + .ok_or_else(|| { ::serde::de::Error::unknown_variant(v, &[]) }) + } + fn visit_i64( + self, + v: i64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_u64( + self, + v: u64, + ) -> ::core::result::Result { + let v32 = i32::try_from(v) + .map_err(|_| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("enum value {v} out of i32 range"), + ) + })?; + ::from_i32(v32) + .ok_or_else(|| { + ::serde::de::Error::custom( + ::buffa::alloc::format!("unknown enum value {v32}"), + ) + }) + } + fn visit_unit( + self, + ) -> ::core::result::Result { + ::core::result::Result::Ok(::core::default::Default::default()) + } + } + d.deserialize_any(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for PaymentPurpose { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +impl ::buffa::Enumeration for PaymentPurpose { + fn from_i32(value: i32) -> ::core::option::Option { + match value { + 0i32 => ::core::option::Option::Some(Self::PAYMENT_PURPOSE_UNSPECIFIED), + 1i32 => ::core::option::Option::Some(Self::PAYMENT_PURPOSE_BOOK), + 2i32 => ::core::option::Option::Some(Self::PAYMENT_PURPOSE_DONATION), + 3i32 => ::core::option::Option::Some(Self::PAYMENT_PURPOSE_BOOST), + _ => ::core::option::Option::None, + } + } + fn to_i32(&self) -> i32 { + *self as i32 + } + fn proto_name(&self) -> &'static str { + match self { + Self::PAYMENT_PURPOSE_UNSPECIFIED => "PAYMENT_PURPOSE_UNSPECIFIED", + Self::PAYMENT_PURPOSE_BOOK => "PAYMENT_PURPOSE_BOOK", + Self::PAYMENT_PURPOSE_DONATION => "PAYMENT_PURPOSE_DONATION", + Self::PAYMENT_PURPOSE_BOOST => "PAYMENT_PURPOSE_BOOST", + } + } + fn from_proto_name(name: &str) -> ::core::option::Option { + match name { + "PAYMENT_PURPOSE_UNSPECIFIED" => { + ::core::option::Option::Some(Self::PAYMENT_PURPOSE_UNSPECIFIED) + } + "PAYMENT_PURPOSE_BOOK" => { + ::core::option::Option::Some(Self::PAYMENT_PURPOSE_BOOK) + } + "PAYMENT_PURPOSE_DONATION" => { + ::core::option::Option::Some(Self::PAYMENT_PURPOSE_DONATION) + } + "PAYMENT_PURPOSE_BOOST" => { + ::core::option::Option::Some(Self::PAYMENT_PURPOSE_BOOST) + } + _ => ::core::option::Option::None, + } + } + fn values() -> &'static [Self] { + &[ + Self::PAYMENT_PURPOSE_UNSPECIFIED, + Self::PAYMENT_PURPOSE_BOOK, + Self::PAYMENT_PURPOSE_DONATION, + Self::PAYMENT_PURPOSE_BOOST, + ] + } +} +/// Maps to payment_intents + payments. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Payment { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `method` + #[serde( + rename = "method", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub method: ::buffa::EnumValue, + /// Field 3: `amount_fcfa` + #[serde( + rename = "amountFcfa", + alias = "amount_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub amount_fcfa: i64, + /// Field 4: `status` + #[serde( + rename = "status", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub status: ::buffa::EnumValue, + /// Field 5: `purpose` + #[serde( + rename = "purpose", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub purpose: ::buffa::EnumValue, + /// Field 6: `platform_transaction_reference` + #[serde( + rename = "platformTransactionReference", + alias = "platform_transaction_reference", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub platform_transaction_reference: ::buffa::alloc::string::String, + /// Field 7: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + /// Field 8: `updated_at` + #[serde( + rename = "updatedAt", + alias = "updated_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub updated_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Payment { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Payment") + .field("id", &self.id) + .field("method", &self.method) + .field("amount_fcfa", &self.amount_fcfa) + .field("status", &self.status) + .field("purpose", &self.purpose) + .field( + "platform_transaction_reference", + &self.platform_transaction_reference, + ) + .field("created_at", &self.created_at) + .field("updated_at", &self.updated_at) + .finish() + } +} +impl Payment { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Payment"; +} +::buffa::impl_default_instance!(Payment); +impl ::buffa::MessageName for Payment { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Payment"; + const FULL_NAME: &'static str = "bookbridge.v1.Payment"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Payment"; +} +impl ::buffa::Message for Payment { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + { + let val = self.method.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.amount_fcfa != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + { + let val = self.purpose.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if !self.platform_transaction_reference.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len( + &self.platform_transaction_reference, + ) as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.updated_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.updated_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + { + let val = self.method.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(2u32, val, buf); + } + } + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(3u32, self.amount_fcfa, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(4u32, val, buf); + } + } + { + let val = self.purpose.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(5u32, val, buf); + } + } + if !self.platform_transaction_reference.is_empty() { + ::buffa::types::put_string_field( + 6u32, + &self.platform_transaction_reference, + buf, + ); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 7u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + if self.updated_at.is_set() { + ::buffa::types::put_len_delimited_header( + 8u32, + u64::from(__cache.consume_next()), + buf, + ); + self.updated_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.method = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.amount_fcfa = ::buffa::types::decode_int64(buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.purpose = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + &mut self.platform_transaction_reference, + buf, + )?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.updated_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.method = ::buffa::EnumValue::from(0); + self.amount_fcfa = 0i64; + self.status = ::buffa::EnumValue::from(0); + self.purpose = ::buffa::EnumValue::from(0); + self.platform_transaction_reference.clear(); + self.created_at = ::buffa::MessageField::none(); + self.updated_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Payment { + const PROTO_FQN: &'static str = "bookbridge.v1.Payment"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Payment { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __PAYMENT_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Payment", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Maps to book_purchases (escrow flow). +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Purchase { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `transaction_id` + #[serde( + rename = "transactionId", + alias = "transaction_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub transaction_id: ::buffa::alloc::string::String, + /// Field 3: `book` + #[serde( + rename = "book", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub book: ::buffa::MessageField< + BookPurchaseDetails, + ::buffa::Inline, + >, + /// Field 4: `buyer_id` + #[serde( + rename = "buyerId", + alias = "buyer_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub buyer_id: ::buffa::alloc::string::String, + /// Field 5: `status` + #[serde( + rename = "status", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub status: ::buffa::EnumValue, + /// Field 6: `confirmed` + #[serde( + rename = "confirmed", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub confirmed: bool, + /// Field 7: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Purchase { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Purchase") + .field("id", &self.id) + .field("transaction_id", &self.transaction_id) + .field("book", &self.book) + .field("buyer_id", &self.buyer_id) + .field("status", &self.status) + .field("confirmed", &self.confirmed) + .field("created_at", &self.created_at) + .finish() + } +} +impl Purchase { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Purchase"; +} +::buffa::impl_default_instance!(Purchase); +impl ::buffa::MessageName for Purchase { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Purchase"; + const FULL_NAME: &'static str = "bookbridge.v1.Purchase"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Purchase"; +} +impl ::buffa::Message for Purchase { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.transaction_id) as u64; + } + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.buyer_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.buyer_id) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.confirmed { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.transaction_id, buf); + } + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 3u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + if !self.buyer_id.is_empty() { + ::buffa::types::put_string_field(4u32, &self.buyer_id, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(5u32, val, buf); + } + } + if self.confirmed { + ::buffa::types::put_bool_field(6u32, self.confirmed, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 7u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.transaction_id, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.book.get_or_insert_default(), + buf, + ctx, + )?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.buyer_id, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.confirmed = ::buffa::types::decode_bool(buf)?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.transaction_id.clear(); + self.book = ::buffa::MessageField::none(); + self.buyer_id.clear(); + self.status = ::buffa::EnumValue::from(0); + self.confirmed = false; + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Purchase { + const PROTO_FQN: &'static str = "bookbridge.v1.Purchase"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Purchase { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __PURCHASE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Purchase", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct BookPurchaseDetails { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + /// Field 2: `title` + #[serde( + rename = "title", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub title: ::buffa::alloc::string::String, + /// Field 3: `cover_url` + #[serde( + rename = "coverUrl", + alias = "cover_url", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub cover_url: ::buffa::alloc::string::String, + /// Field 4: `price_fcfa` + #[serde( + rename = "priceFcfa", + alias = "price_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub price_fcfa: i64, + /// Field 5: `meetup_location` + #[serde( + rename = "meetupLocation", + alias = "meetup_location", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub meetup_location: ::buffa::MessageField< + MeetupLocation, + ::buffa::Inline, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for BookPurchaseDetails { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("BookPurchaseDetails") + .field("book_id", &self.book_id) + .field("title", &self.title) + .field("cover_url", &self.cover_url) + .field("price_fcfa", &self.price_fcfa) + .field("meetup_location", &self.meetup_location) + .finish() + } +} +impl BookPurchaseDetails { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookPurchaseDetails"; +} +::buffa::impl_default_instance!(BookPurchaseDetails); +impl ::buffa::MessageName for BookPurchaseDetails { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "BookPurchaseDetails"; + const FULL_NAME: &'static str = "bookbridge.v1.BookPurchaseDetails"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookPurchaseDetails"; +} +impl ::buffa::Message for BookPurchaseDetails { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if !self.title.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.cover_url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.cover_url) as u64; + } + if self.price_fcfa != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.price_fcfa) as u64; + } + if self.meetup_location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.meetup_location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + if !self.title.is_empty() { + ::buffa::types::put_string_field(2u32, &self.title, buf); + } + if !self.cover_url.is_empty() { + ::buffa::types::put_string_field(3u32, &self.cover_url, buf); + } + if self.price_fcfa != 0i64 { + ::buffa::types::put_int64_field(4u32, self.price_fcfa, buf); + } + if self.meetup_location.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.meetup_location.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.title, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.cover_url, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.price_fcfa = ::buffa::types::decode_int64(buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.meetup_location.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.title.clear(); + self.cover_url.clear(); + self.price_fcfa = 0i64; + self.meetup_location = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for BookPurchaseDetails { + const PROTO_FQN: &'static str = "bookbridge.v1.BookPurchaseDetails"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for BookPurchaseDetails { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __BOOK_PURCHASE_DETAILS_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.BookPurchaseDetails", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateBookPurchaseRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + /// Field 2: `meetup_location_id` + #[serde( + rename = "meetupLocationId", + alias = "meetup_location_id", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub meetup_location_id: ::core::option::Option<::buffa::alloc::string::String>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateBookPurchaseRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateBookPurchaseRequest") + .field("book_id", &self.book_id) + .field("meetup_location_id", &self.meetup_location_id) + .finish() + } +} +impl CreateBookPurchaseRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookPurchaseRequest"; +} +impl CreateBookPurchaseRequest { + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::meetup_location_id`] to `Some(value)`, consuming and returning `self`. + pub fn with_meetup_location_id( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.meetup_location_id = Some(value.into()); + self + } +} +::buffa::impl_default_instance!(CreateBookPurchaseRequest); +impl ::buffa::MessageName for CreateBookPurchaseRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBookPurchaseRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBookPurchaseRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookPurchaseRequest"; +} +impl ::buffa::Message for CreateBookPurchaseRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if let Some(ref v) = self.meetup_location_id { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + if let Some(ref v) = self.meetup_location_id { + ::buffa::types::put_string_field(2u32, v, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string( + self + .meetup_location_id + .get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.meetup_location_id = ::core::option::Option::None; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateBookPurchaseRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateBookPurchaseRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateBookPurchaseRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_BOOK_PURCHASE_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateBookPurchaseRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateBookPurchaseResponse { + /// Field 1: `purchase` + #[serde( + rename = "purchase", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub purchase: ::buffa::MessageField>, + /// Fapshi session identifier to poll for confirmation. + /// + /// Field 2: `fapshi_transaction_id` + #[serde( + rename = "fapshiTransactionId", + alias = "fapshi_transaction_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub fapshi_transaction_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateBookPurchaseResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateBookPurchaseResponse") + .field("purchase", &self.purchase) + .field("fapshi_transaction_id", &self.fapshi_transaction_id) + .finish() + } +} +impl CreateBookPurchaseResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookPurchaseResponse"; +} +::buffa::impl_default_instance!(CreateBookPurchaseResponse); +impl ::buffa::MessageName for CreateBookPurchaseResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBookPurchaseResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBookPurchaseResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookPurchaseResponse"; +} +impl ::buffa::Message for CreateBookPurchaseResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.purchase.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.purchase.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.fapshi_transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.fapshi_transaction_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.purchase.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.purchase.write_to(__cache, buf); + } + if !self.fapshi_transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.fapshi_transaction_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.purchase.get_or_insert_default(), + buf, + ctx, + )?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.fapshi_transaction_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.purchase = ::buffa::MessageField::none(); + self.fapshi_transaction_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateBookPurchaseResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateBookPurchaseResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateBookPurchaseResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_BOOK_PURCHASE_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateBookPurchaseResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetPurchaseRequest { + /// Field 1: `purchase_id` + #[serde( + rename = "purchaseId", + alias = "purchase_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub purchase_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetPurchaseRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetPurchaseRequest") + .field("purchase_id", &self.purchase_id) + .finish() + } +} +impl GetPurchaseRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPurchaseRequest"; +} +::buffa::impl_default_instance!(GetPurchaseRequest); +impl ::buffa::MessageName for GetPurchaseRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetPurchaseRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetPurchaseRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPurchaseRequest"; +} +impl ::buffa::Message for GetPurchaseRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.purchase_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.purchase_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.purchase_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.purchase_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.purchase_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.purchase_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetPurchaseRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetPurchaseRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetPurchaseRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_PURCHASE_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetPurchaseRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetPurchaseResponse { + /// Field 1: `purchase` + #[serde( + rename = "purchase", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub purchase: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetPurchaseResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetPurchaseResponse").field("purchase", &self.purchase).finish() + } +} +impl GetPurchaseResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPurchaseResponse"; +} +::buffa::impl_default_instance!(GetPurchaseResponse); +impl ::buffa::MessageName for GetPurchaseResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetPurchaseResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetPurchaseResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPurchaseResponse"; +} +impl ::buffa::Message for GetPurchaseResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.purchase.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.purchase.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.purchase.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.purchase.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.purchase.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.purchase = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetPurchaseResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetPurchaseResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetPurchaseResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_PURCHASE_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetPurchaseResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMyPurchasesRequest { + /// Field 1: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 2: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMyPurchasesRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMyPurchasesRequest") + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .finish() + } +} +impl ListMyPurchasesRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyPurchasesRequest"; +} +::buffa::impl_default_instance!(ListMyPurchasesRequest); +impl ::buffa::MessageName for ListMyPurchasesRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMyPurchasesRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMyPurchasesRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyPurchasesRequest"; +} +impl ::buffa::Message for ListMyPurchasesRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.page_token.clear(); + self.page_size = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMyPurchasesRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMyPurchasesRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMyPurchasesRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MY_PURCHASES_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMyPurchasesRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMyPurchasesResponse { + /// Field 1: `purchases` + #[serde( + rename = "purchases", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub purchases: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMyPurchasesResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMyPurchasesResponse") + .field("purchases", &self.purchases) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListMyPurchasesResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyPurchasesResponse"; +} +::buffa::impl_default_instance!(ListMyPurchasesResponse); +impl ::buffa::MessageName for ListMyPurchasesResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMyPurchasesResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMyPurchasesResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyPurchasesResponse"; +} +impl ::buffa::Message for ListMyPurchasesResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.purchases { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.purchases { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.purchases.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.purchases.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMyPurchasesResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMyPurchasesResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMyPurchasesResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MY_PURCHASES_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMyPurchasesResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMySalesRequest { + /// Field 1: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 2: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMySalesRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMySalesRequest") + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .finish() + } +} +impl ListMySalesRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMySalesRequest"; +} +::buffa::impl_default_instance!(ListMySalesRequest); +impl ::buffa::MessageName for ListMySalesRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMySalesRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMySalesRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMySalesRequest"; +} +impl ::buffa::Message for ListMySalesRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.page_token.clear(); + self.page_size = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMySalesRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMySalesRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMySalesRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MY_SALES_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMySalesRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Sale { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `transaction_id` + #[serde( + rename = "transactionId", + alias = "transaction_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub transaction_id: ::buffa::alloc::string::String, + /// Field 3: `book` + #[serde( + rename = "book", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub book: ::buffa::MessageField< + BookPurchaseDetails, + ::buffa::Inline, + >, + /// Field 4: `buyer_id` + #[serde( + rename = "buyerId", + alias = "buyer_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub buyer_id: ::buffa::alloc::string::String, + /// Field 5: `status` + #[serde( + rename = "status", + with = "::buffa::json_helpers::proto_enum", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_default_enum_value" + )] + pub status: ::buffa::EnumValue, + /// Field 6: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Sale { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Sale") + .field("id", &self.id) + .field("transaction_id", &self.transaction_id) + .field("book", &self.book) + .field("buyer_id", &self.buyer_id) + .field("status", &self.status) + .field("created_at", &self.created_at) + .finish() + } +} +impl Sale { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Sale"; +} +::buffa::impl_default_instance!(Sale); +impl ::buffa::MessageName for Sale { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Sale"; + const FULL_NAME: &'static str = "bookbridge.v1.Sale"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Sale"; +} +impl ::buffa::Message for Sale { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.transaction_id) as u64; + } + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.buyer_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.buyer_id) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.transaction_id, buf); + } + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 3u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + if !self.buyer_id.is_empty() { + ::buffa::types::put_string_field(4u32, &self.buyer_id, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(5u32, val, buf); + } + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.transaction_id, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.book.get_or_insert_default(), + buf, + ctx, + )?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.buyer_id, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(buf)?, + ); + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.transaction_id.clear(); + self.book = ::buffa::MessageField::none(); + self.buyer_id.clear(); + self.status = ::buffa::EnumValue::from(0); + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Sale { + const PROTO_FQN: &'static str = "bookbridge.v1.Sale"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Sale { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __SALE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Sale", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListMySalesResponse { + /// Field 1: `sales` + #[serde( + rename = "sales", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub sales: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListMySalesResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListMySalesResponse") + .field("sales", &self.sales) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListMySalesResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMySalesResponse"; +} +::buffa::impl_default_instance!(ListMySalesResponse); +impl ::buffa::MessageName for ListMySalesResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMySalesResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMySalesResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMySalesResponse"; +} +impl ::buffa::Message for ListMySalesResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.sales { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.sales { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.sales.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.sales.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListMySalesResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListMySalesResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListMySalesResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_MY_SALES_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListMySalesResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ConfirmReceiptRequest { + /// Field 1: `purchase_id` + #[serde( + rename = "purchaseId", + alias = "purchase_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub purchase_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ConfirmReceiptRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ConfirmReceiptRequest") + .field("purchase_id", &self.purchase_id) + .finish() + } +} +impl ConfirmReceiptRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ConfirmReceiptRequest"; +} +::buffa::impl_default_instance!(ConfirmReceiptRequest); +impl ::buffa::MessageName for ConfirmReceiptRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ConfirmReceiptRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ConfirmReceiptRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ConfirmReceiptRequest"; +} +impl ::buffa::Message for ConfirmReceiptRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.purchase_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.purchase_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.purchase_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.purchase_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.purchase_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.purchase_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ConfirmReceiptRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ConfirmReceiptRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ConfirmReceiptRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CONFIRM_RECEIPT_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ConfirmReceiptRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ConfirmReceiptResponse { + /// Field 1: `purchase` + #[serde( + rename = "purchase", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub purchase: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ConfirmReceiptResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ConfirmReceiptResponse") + .field("purchase", &self.purchase) + .finish() + } +} +impl ConfirmReceiptResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ConfirmReceiptResponse"; +} +::buffa::impl_default_instance!(ConfirmReceiptResponse); +impl ::buffa::MessageName for ConfirmReceiptResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ConfirmReceiptResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ConfirmReceiptResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ConfirmReceiptResponse"; +} +impl ::buffa::Message for ConfirmReceiptResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.purchase.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.purchase.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.purchase.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.purchase.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.purchase.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.purchase = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ConfirmReceiptResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ConfirmReceiptResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ConfirmReceiptResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CONFIRM_RECEIPT_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ConfirmReceiptResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct DisputePurchaseRequest { + /// Field 1: `purchase_id` + #[serde( + rename = "purchaseId", + alias = "purchase_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub purchase_id: ::buffa::alloc::string::String, + /// Field 2: `reason` + #[serde( + rename = "reason", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub reason: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for DisputePurchaseRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DisputePurchaseRequest") + .field("purchase_id", &self.purchase_id) + .field("reason", &self.reason) + .finish() + } +} +impl DisputePurchaseRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DisputePurchaseRequest"; +} +::buffa::impl_default_instance!(DisputePurchaseRequest); +impl ::buffa::MessageName for DisputePurchaseRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DisputePurchaseRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.DisputePurchaseRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DisputePurchaseRequest"; +} +impl ::buffa::Message for DisputePurchaseRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.purchase_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.purchase_id) as u64; + } + if !self.reason.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.reason) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.purchase_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.purchase_id, buf); + } + if !self.reason.is_empty() { + ::buffa::types::put_string_field(2u32, &self.reason, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.purchase_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.reason, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.purchase_id.clear(); + self.reason.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for DisputePurchaseRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.DisputePurchaseRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for DisputePurchaseRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DISPUTE_PURCHASE_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.DisputePurchaseRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct DisputePurchaseResponse { + /// Field 1: `purchase` + #[serde( + rename = "purchase", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub purchase: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for DisputePurchaseResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DisputePurchaseResponse") + .field("purchase", &self.purchase) + .finish() + } +} +impl DisputePurchaseResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DisputePurchaseResponse"; +} +::buffa::impl_default_instance!(DisputePurchaseResponse); +impl ::buffa::MessageName for DisputePurchaseResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DisputePurchaseResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.DisputePurchaseResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DisputePurchaseResponse"; +} +impl ::buffa::Message for DisputePurchaseResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.purchase.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.purchase.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.purchase.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.purchase.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.purchase.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.purchase = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for DisputePurchaseResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.DisputePurchaseResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for DisputePurchaseResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DISPUTE_PURCHASE_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.DisputePurchaseResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Maps to the reviews table. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Review { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `author` + #[serde( + rename = "author", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub author: ::buffa::MessageField>, + /// Field 3: `reviewee_id` + #[serde( + rename = "revieweeId", + alias = "reviewee_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub reviewee_id: ::buffa::alloc::string::String, + /// Field 4: `rating` + #[serde( + rename = "rating", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub rating: i32, + /// Field 5: `content` + #[serde( + rename = "content", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub content: ::buffa::alloc::string::String, + /// Field 6: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Review { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Review") + .field("id", &self.id) + .field("author", &self.author) + .field("reviewee_id", &self.reviewee_id) + .field("rating", &self.rating) + .field("content", &self.content) + .field("created_at", &self.created_at) + .finish() + } +} +impl Review { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Review"; +} +::buffa::impl_default_instance!(Review); +impl ::buffa::MessageName for Review { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Review"; + const FULL_NAME: &'static str = "bookbridge.v1.Review"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Review"; +} +impl ::buffa::Message for Review { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if self.author.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.author.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.reviewee_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.reviewee_id) as u64; + } + if self.rating != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.rating) as u64; + } + if !self.content.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.content) as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if self.author.is_set() { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + self.author.write_to(__cache, buf); + } + if !self.reviewee_id.is_empty() { + ::buffa::types::put_string_field(3u32, &self.reviewee_id, buf); + } + if self.rating != 0i32 { + ::buffa::types::put_int32_field(4u32, self.rating, buf); + } + if !self.content.is_empty() { + ::buffa::types::put_string_field(5u32, &self.content, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.author.get_or_insert_default(), + buf, + ctx, + )?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.reviewee_id, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.rating = ::buffa::types::decode_int32(buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.content, buf)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.author = ::buffa::MessageField::none(); + self.reviewee_id.clear(); + self.rating = 0i32; + self.content.clear(); + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Review { + const PROTO_FQN: &'static str = "bookbridge.v1.Review"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Review { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __REVIEW_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Review", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateReviewRequest { + /// Field 1: `reviewee_id` + #[serde( + rename = "revieweeId", + alias = "reviewee_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub reviewee_id: ::buffa::alloc::string::String, + /// Field 2: `transaction_id` + #[serde( + rename = "transactionId", + alias = "transaction_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub transaction_id: ::buffa::alloc::string::String, + /// Field 3: `rating` + #[serde( + rename = "rating", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub rating: i32, + /// Field 4: `content` + #[serde( + rename = "content", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub content: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateReviewRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateReviewRequest") + .field("reviewee_id", &self.reviewee_id) + .field("transaction_id", &self.transaction_id) + .field("rating", &self.rating) + .field("content", &self.content) + .finish() + } +} +impl CreateReviewRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateReviewRequest"; +} +::buffa::impl_default_instance!(CreateReviewRequest); +impl ::buffa::MessageName for CreateReviewRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateReviewRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateReviewRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateReviewRequest"; +} +impl ::buffa::Message for CreateReviewRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.reviewee_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.reviewee_id) as u64; + } + if !self.transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.transaction_id) as u64; + } + if self.rating != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.rating) as u64; + } + if !self.content.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.content) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.reviewee_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.reviewee_id, buf); + } + if !self.transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.transaction_id, buf); + } + if self.rating != 0i32 { + ::buffa::types::put_int32_field(3u32, self.rating, buf); + } + if !self.content.is_empty() { + ::buffa::types::put_string_field(4u32, &self.content, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.reviewee_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.transaction_id, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.rating = ::buffa::types::decode_int32(buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.content, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.reviewee_id.clear(); + self.transaction_id.clear(); + self.rating = 0i32; + self.content.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateReviewRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateReviewRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateReviewRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_REVIEW_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateReviewRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateReviewResponse { + /// Field 1: `review` + #[serde( + rename = "review", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub review: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateReviewResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateReviewResponse").field("review", &self.review).finish() + } +} +impl CreateReviewResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateReviewResponse"; +} +::buffa::impl_default_instance!(CreateReviewResponse); +impl ::buffa::MessageName for CreateReviewResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateReviewResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateReviewResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateReviewResponse"; +} +impl ::buffa::Message for CreateReviewResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.review.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.review.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.review.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.review.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.review.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.review = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateReviewResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateReviewResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateReviewResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_REVIEW_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateReviewResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListUserReviewsRequest { + /// Field 1: `user_id` + #[serde( + rename = "userId", + alias = "user_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub user_id: ::buffa::alloc::string::String, + /// Field 2: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 3: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListUserReviewsRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListUserReviewsRequest") + .field("user_id", &self.user_id) + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .finish() + } +} +impl ListUserReviewsRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListUserReviewsRequest"; +} +::buffa::impl_default_instance!(ListUserReviewsRequest); +impl ::buffa::MessageName for ListUserReviewsRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListUserReviewsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListUserReviewsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListUserReviewsRequest"; +} +impl ::buffa::Message for ListUserReviewsRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.user_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.user_id) as u64; + } + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.user_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.user_id, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(3u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.user_id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.user_id.clear(); + self.page_token.clear(); + self.page_size = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListUserReviewsRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListUserReviewsRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListUserReviewsRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_USER_REVIEWS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListUserReviewsRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListUserReviewsResponse { + /// Field 1: `reviews` + #[serde( + rename = "reviews", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub reviews: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListUserReviewsResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListUserReviewsResponse") + .field("reviews", &self.reviews) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListUserReviewsResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListUserReviewsResponse"; +} +::buffa::impl_default_instance!(ListUserReviewsResponse); +impl ::buffa::MessageName for ListUserReviewsResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListUserReviewsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListUserReviewsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListUserReviewsResponse"; +} +impl ::buffa::Message for ListUserReviewsResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.reviews { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.reviews { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.reviews.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.reviews.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListUserReviewsResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListUserReviewsResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListUserReviewsResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_USER_REVIEWS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListUserReviewsResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct HasReviewedTransactionRequest { + /// Field 1: `transaction_id` + #[serde( + rename = "transactionId", + alias = "transaction_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub transaction_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for HasReviewedTransactionRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("HasReviewedTransactionRequest") + .field("transaction_id", &self.transaction_id) + .finish() + } +} +impl HasReviewedTransactionRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.HasReviewedTransactionRequest"; +} +::buffa::impl_default_instance!(HasReviewedTransactionRequest); +impl ::buffa::MessageName for HasReviewedTransactionRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "HasReviewedTransactionRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.HasReviewedTransactionRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.HasReviewedTransactionRequest"; +} +impl ::buffa::Message for HasReviewedTransactionRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.transaction_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.transaction_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.transaction_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.transaction_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.transaction_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for HasReviewedTransactionRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.HasReviewedTransactionRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for HasReviewedTransactionRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __HAS_REVIEWED_TRANSACTION_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.HasReviewedTransactionRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct HasReviewedTransactionResponse { + /// Field 1: `has_reviewed` + #[serde( + rename = "hasReviewed", + alias = "has_reviewed", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub has_reviewed: bool, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for HasReviewedTransactionResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("HasReviewedTransactionResponse") + .field("has_reviewed", &self.has_reviewed) + .finish() + } +} +impl HasReviewedTransactionResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.HasReviewedTransactionResponse"; +} +::buffa::impl_default_instance!(HasReviewedTransactionResponse); +impl ::buffa::MessageName for HasReviewedTransactionResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "HasReviewedTransactionResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.HasReviewedTransactionResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.HasReviewedTransactionResponse"; +} +impl ::buffa::Message for HasReviewedTransactionResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.has_reviewed { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.has_reviewed { + ::buffa::types::put_bool_field(1u32, self.has_reviewed, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.has_reviewed = ::buffa::types::decode_bool(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.has_reviewed = false; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for HasReviewedTransactionResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.HasReviewedTransactionResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for HasReviewedTransactionResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __HAS_REVIEWED_TRANSACTION_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.HasReviewedTransactionResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Aggregate platform statistics for the impact screen. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct PlatformStats { + /// Field 1: `total_books_circulated` + #[serde( + rename = "totalBooksCirculated", + alias = "total_books_circulated", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub total_books_circulated: i64, + /// Field 2: `total_students_reached` + #[serde( + rename = "totalStudentsReached", + alias = "total_students_reached", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub total_students_reached: i64, + /// Field 3: `total_money_saved_fcfa` + #[serde( + rename = "totalMoneySavedFcfa", + alias = "total_money_saved_fcfa", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub total_money_saved_fcfa: i64, + /// Field 4: `total_co2_avoided_kg` + #[serde( + rename = "totalCo2AvoidedKg", + alias = "total_co2_avoided_kg", + with = "::buffa::json_helpers::double", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_f64" + )] + pub total_co2_avoided_kg: f64, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for PlatformStats { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("PlatformStats") + .field("total_books_circulated", &self.total_books_circulated) + .field("total_students_reached", &self.total_students_reached) + .field("total_money_saved_fcfa", &self.total_money_saved_fcfa) + .field("total_co2_avoided_kg", &self.total_co2_avoided_kg) + .finish() + } +} +impl PlatformStats { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.PlatformStats"; +} +::buffa::impl_default_instance!(PlatformStats); +impl ::buffa::MessageName for PlatformStats { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "PlatformStats"; + const FULL_NAME: &'static str = "bookbridge.v1.PlatformStats"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.PlatformStats"; +} +impl ::buffa::Message for PlatformStats { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.total_books_circulated != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.total_books_circulated) + as u64; + } + if self.total_students_reached != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.total_students_reached) + as u64; + } + if self.total_money_saved_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.total_money_saved_fcfa) + as u64; + } + if self.total_co2_avoided_kg.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.total_books_circulated != 0i64 { + ::buffa::types::put_int64_field(1u32, self.total_books_circulated, buf); + } + if self.total_students_reached != 0i64 { + ::buffa::types::put_int64_field(2u32, self.total_students_reached, buf); + } + if self.total_money_saved_fcfa != 0i64 { + ::buffa::types::put_int64_field(3u32, self.total_money_saved_fcfa, buf); + } + if self.total_co2_avoided_kg.to_bits() != 0u64 { + ::buffa::types::put_double_field(4u32, self.total_co2_avoided_kg, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.total_books_circulated = ::buffa::types::decode_int64(buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.total_students_reached = ::buffa::types::decode_int64(buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.total_money_saved_fcfa = ::buffa::types::decode_int64(buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + self.total_co2_avoided_kg = ::buffa::types::decode_double(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.total_books_circulated = 0i64; + self.total_students_reached = 0i64; + self.total_money_saved_fcfa = 0i64; + self.total_co2_avoided_kg = 0f64; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for PlatformStats { + const PROTO_FQN: &'static str = "bookbridge.v1.PlatformStats"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for PlatformStats { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __PLATFORM_STATS_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.PlatformStats", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetPlatformStatsRequest { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetPlatformStatsRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetPlatformStatsRequest").finish() + } +} +impl GetPlatformStatsRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPlatformStatsRequest"; +} +::buffa::impl_default_instance!(GetPlatformStatsRequest); +impl ::buffa::MessageName for GetPlatformStatsRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetPlatformStatsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetPlatformStatsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPlatformStatsRequest"; +} +impl ::buffa::Message for GetPlatformStatsRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetPlatformStatsRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetPlatformStatsRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetPlatformStatsRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_PLATFORM_STATS_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetPlatformStatsRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetPlatformStatsResponse { + /// Field 1: `stats` + #[serde( + rename = "stats", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub stats: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetPlatformStatsResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetPlatformStatsResponse").field("stats", &self.stats).finish() + } +} +impl GetPlatformStatsResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPlatformStatsResponse"; +} +::buffa::impl_default_instance!(GetPlatformStatsResponse); +impl ::buffa::MessageName for GetPlatformStatsResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetPlatformStatsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetPlatformStatsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPlatformStatsResponse"; +} +impl ::buffa::Message for GetPlatformStatsResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.stats.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.stats.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.stats.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.stats.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.stats.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.stats = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetPlatformStatsResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetPlatformStatsResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetPlatformStatsResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_PLATFORM_STATS_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetPlatformStatsResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +/// Maps to the uploads table. +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct Upload { + /// Field 1: `id` + #[serde( + rename = "id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub id: ::buffa::alloc::string::String, + /// Field 2: `storage_key` + #[serde( + rename = "storageKey", + alias = "storage_key", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub storage_key: ::buffa::alloc::string::String, + /// Field 3: `file_name` + #[serde( + rename = "fileName", + alias = "file_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub file_name: ::buffa::alloc::string::String, + /// Field 4: `content_type` + #[serde( + rename = "contentType", + alias = "content_type", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub content_type: ::buffa::alloc::string::String, + /// Field 5: `size_bytes` + #[serde( + rename = "sizeBytes", + alias = "size_bytes", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub size_bytes: i64, + /// Field 6: `url` + #[serde( + rename = "url", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub url: ::buffa::alloc::string::String, + /// Field 7: `created_at` + #[serde( + rename = "createdAt", + alias = "created_at", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub created_at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for Upload { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("Upload") + .field("id", &self.id) + .field("storage_key", &self.storage_key) + .field("file_name", &self.file_name) + .field("content_type", &self.content_type) + .field("size_bytes", &self.size_bytes) + .field("url", &self.url) + .field("created_at", &self.created_at) + .finish() + } +} +impl Upload { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Upload"; +} +::buffa::impl_default_instance!(Upload); +impl ::buffa::MessageName for Upload { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Upload"; + const FULL_NAME: &'static str = "bookbridge.v1.Upload"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Upload"; +} +impl ::buffa::Message for Upload { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.storage_key.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.storage_key) as u64; + } + if !self.file_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.file_name) as u64; + } + if !self.content_type.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.content_type) as u64; + } + if self.size_bytes != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.size_bytes) as u64; + } + if !self.url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.url) as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.storage_key.is_empty() { + ::buffa::types::put_string_field(2u32, &self.storage_key, buf); + } + if !self.file_name.is_empty() { + ::buffa::types::put_string_field(3u32, &self.file_name, buf); + } + if !self.content_type.is_empty() { + ::buffa::types::put_string_field(4u32, &self.content_type, buf); + } + if self.size_bytes != 0i64 { + ::buffa::types::put_int64_field(5u32, self.size_bytes, buf); + } + if !self.url.is_empty() { + ::buffa::types::put_string_field(6u32, &self.url, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 7u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.id, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.storage_key, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.file_name, buf)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.content_type, buf)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.size_bytes = ::buffa::types::decode_int64(buf)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.url, buf)?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.created_at.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.id.clear(); + self.storage_key.clear(); + self.file_name.clear(); + self.content_type.clear(); + self.size_bytes = 0i64; + self.url.clear(); + self.created_at = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for Upload { + const PROTO_FQN: &'static str = "bookbridge.v1.Upload"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for Upload { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __UPLOAD_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.Upload", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateUploadRequest { + /// Field 1: `file_name` + #[serde( + rename = "fileName", + alias = "file_name", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub file_name: ::buffa::alloc::string::String, + /// Field 2: `content_type` + #[serde( + rename = "contentType", + alias = "content_type", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub content_type: ::buffa::alloc::string::String, + /// Field 3: `size_bytes` + #[serde( + rename = "sizeBytes", + alias = "size_bytes", + with = "::buffa::json_helpers::int64", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i64" + )] + pub size_bytes: i64, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateUploadRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateUploadRequest") + .field("file_name", &self.file_name) + .field("content_type", &self.content_type) + .field("size_bytes", &self.size_bytes) + .finish() + } +} +impl CreateUploadRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateUploadRequest"; +} +::buffa::impl_default_instance!(CreateUploadRequest); +impl ::buffa::MessageName for CreateUploadRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateUploadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateUploadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateUploadRequest"; +} +impl ::buffa::Message for CreateUploadRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.file_name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.file_name) as u64; + } + if !self.content_type.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.content_type) as u64; + } + if self.size_bytes != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.size_bytes) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.file_name.is_empty() { + ::buffa::types::put_string_field(1u32, &self.file_name, buf); + } + if !self.content_type.is_empty() { + ::buffa::types::put_string_field(2u32, &self.content_type, buf); + } + if self.size_bytes != 0i64 { + ::buffa::types::put_int64_field(3u32, self.size_bytes, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.file_name, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.content_type, buf)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.size_bytes = ::buffa::types::decode_int64(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.file_name.clear(); + self.content_type.clear(); + self.size_bytes = 0i64; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateUploadRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateUploadRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateUploadRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_UPLOAD_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateUploadRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CreateUploadResponse { + /// Field 1: `upload` + #[serde( + rename = "upload", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub upload: ::buffa::MessageField>, + /// Pre-signed PUT target the client uploads the bytes to. + /// + /// Field 2: `upload_url` + #[serde( + rename = "uploadUrl", + alias = "upload_url", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub upload_url: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CreateUploadResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CreateUploadResponse") + .field("upload", &self.upload) + .field("upload_url", &self.upload_url) + .finish() + } +} +impl CreateUploadResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateUploadResponse"; +} +::buffa::impl_default_instance!(CreateUploadResponse); +impl ::buffa::MessageName for CreateUploadResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateUploadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateUploadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateUploadResponse"; +} +impl ::buffa::Message for CreateUploadResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.upload.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.upload.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.upload_url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.upload_url) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.upload.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.upload.write_to(__cache, buf); + } + if !self.upload_url.is_empty() { + ::buffa::types::put_string_field(2u32, &self.upload_url, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.upload.get_or_insert_default(), + buf, + ctx, + )?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.upload_url, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.upload = ::buffa::MessageField::none(); + self.upload_url.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CreateUploadResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.CreateUploadResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CreateUploadResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __CREATE_UPLOAD_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CreateUploadResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CompleteUploadRequest { + /// Field 1: `upload_id` + #[serde( + rename = "uploadId", + alias = "upload_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub upload_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CompleteUploadRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CompleteUploadRequest") + .field("upload_id", &self.upload_id) + .finish() + } +} +impl CompleteUploadRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CompleteUploadRequest"; +} +::buffa::impl_default_instance!(CompleteUploadRequest); +impl ::buffa::MessageName for CompleteUploadRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CompleteUploadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CompleteUploadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CompleteUploadRequest"; +} +impl ::buffa::Message for CompleteUploadRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.upload_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.upload_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CompleteUploadRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.CompleteUploadRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CompleteUploadRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __COMPLETE_UPLOAD_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CompleteUploadRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct CompleteUploadResponse { + /// Field 1: `upload` + #[serde( + rename = "upload", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub upload: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for CompleteUploadResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("CompleteUploadResponse").field("upload", &self.upload).finish() + } +} +impl CompleteUploadResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CompleteUploadResponse"; +} +::buffa::impl_default_instance!(CompleteUploadResponse); +impl ::buffa::MessageName for CompleteUploadResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CompleteUploadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CompleteUploadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CompleteUploadResponse"; +} +impl ::buffa::Message for CompleteUploadResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.upload.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.upload.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.upload.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.upload.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.upload.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.upload = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for CompleteUploadResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.CompleteUploadResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for CompleteUploadResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __COMPLETE_UPLOAD_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.CompleteUploadResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetUploadRequest { + /// Field 1: `upload_id` + #[serde( + rename = "uploadId", + alias = "upload_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub upload_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetUploadRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetUploadRequest").field("upload_id", &self.upload_id).finish() + } +} +impl GetUploadRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUploadRequest"; +} +::buffa::impl_default_instance!(GetUploadRequest); +impl ::buffa::MessageName for GetUploadRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetUploadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetUploadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUploadRequest"; +} +impl ::buffa::Message for GetUploadRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.upload_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.upload_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetUploadRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetUploadRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetUploadRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_UPLOAD_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetUploadRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetUploadResponse { + /// Field 1: `upload` + #[serde( + rename = "upload", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub upload: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetUploadResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetUploadResponse").field("upload", &self.upload).finish() + } +} +impl GetUploadResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUploadResponse"; +} +::buffa::impl_default_instance!(GetUploadResponse); +impl ::buffa::MessageName for GetUploadResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetUploadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetUploadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUploadResponse"; +} +impl ::buffa::Message for GetUploadResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.upload.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.upload.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.upload.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.upload.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.upload.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.upload = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetUploadResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetUploadResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetUploadResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_UPLOAD_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetUploadResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct DeleteUploadRequest { + /// Field 1: `upload_id` + #[serde( + rename = "uploadId", + alias = "upload_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub upload_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for DeleteUploadRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DeleteUploadRequest") + .field("upload_id", &self.upload_id) + .finish() + } +} +impl DeleteUploadRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteUploadRequest"; +} +::buffa::impl_default_instance!(DeleteUploadRequest); +impl ::buffa::MessageName for DeleteUploadRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DeleteUploadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.DeleteUploadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteUploadRequest"; +} +impl ::buffa::Message for DeleteUploadRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.upload_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.upload_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for DeleteUploadRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.DeleteUploadRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for DeleteUploadRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DELETE_UPLOAD_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.DeleteUploadRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct DeleteUploadResponse { + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for DeleteUploadResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DeleteUploadResponse").finish() + } +} +impl DeleteUploadResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteUploadResponse"; +} +::buffa::impl_default_instance!(DeleteUploadResponse); +impl ::buffa::MessageName for DeleteUploadResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DeleteUploadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.DeleteUploadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteUploadResponse"; +} +impl ::buffa::Message for DeleteUploadResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for DeleteUploadResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.DeleteUploadResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for DeleteUploadResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DELETE_UPLOAD_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.DeleteUploadResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetUserRequest { + /// Field 1: `user_id` + #[serde( + rename = "userId", + alias = "user_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub user_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetUserRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetUserRequest").field("user_id", &self.user_id).finish() + } +} +impl GetUserRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUserRequest"; +} +::buffa::impl_default_instance!(GetUserRequest); +impl ::buffa::MessageName for GetUserRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetUserRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetUserRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUserRequest"; +} +impl ::buffa::Message for GetUserRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.user_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.user_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.user_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.user_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.user_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.user_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetUserRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.GetUserRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetUserRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_USER_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetUserRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct GetUserResponse { + /// Field 1: `user` + #[serde( + rename = "user", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub user: ::buffa::MessageField>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for GetUserResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("GetUserResponse").field("user", &self.user).finish() + } +} +impl GetUserResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUserResponse"; +} +::buffa::impl_default_instance!(GetUserResponse); +impl ::buffa::MessageName for GetUserResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetUserResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetUserResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUserResponse"; +} +impl ::buffa::Message for GetUserResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.user.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.user.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.user.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.user.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::Message::merge_length_delimited( + self.user.get_or_insert_default(), + buf, + ctx, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.user = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for GetUserResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.GetUserResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for GetUserResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __GET_USER_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.GetUserResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListWishlistRequest { + /// Field 1: `page_token` + #[serde( + rename = "pageToken", + alias = "page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub page_token: ::buffa::alloc::string::String, + /// Field 2: `page_size` + #[serde( + rename = "pageSize", + alias = "page_size", + with = "::buffa::json_helpers::int32", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_zero_i32" + )] + pub page_size: i32, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListWishlistRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListWishlistRequest") + .field("page_token", &self.page_token) + .field("page_size", &self.page_size) + .finish() + } +} +impl ListWishlistRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListWishlistRequest"; +} +::buffa::impl_default_instance!(ListWishlistRequest); +impl ::buffa::MessageName for ListWishlistRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListWishlistRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListWishlistRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListWishlistRequest"; +} +impl ::buffa::Message for ListWishlistRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.page_token) as u64; + } + if self.page_size != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.page_token, buf)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.page_size = ::buffa::types::decode_int32(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.page_token.clear(); + self.page_size = 0i32; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListWishlistRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.ListWishlistRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListWishlistRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_WISHLIST_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListWishlistRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct ListWishlistResponse { + /// Field 1: `books` + #[serde( + rename = "books", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_vec", + deserialize_with = "::buffa::json_helpers::null_as_default" + )] + pub books: ::buffa::alloc::vec::Vec, + /// Field 2: `next_page_token` + #[serde( + rename = "nextPageToken", + alias = "next_page_token", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub next_page_token: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for ListWishlistResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("ListWishlistResponse") + .field("books", &self.books) + .field("next_page_token", &self.next_page_token) + .finish() + } +} +impl ListWishlistResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListWishlistResponse"; +} +::buffa::impl_default_instance!(ListWishlistResponse); +impl ::buffa::MessageName for ListWishlistResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListWishlistResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListWishlistResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListWishlistResponse"; +} +impl ::buffa::Message for ListWishlistResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let mut elem = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&elem), + )?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; + self.books.push(elem); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.next_page_token, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.books.clear(); + self.next_page_token.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for ListWishlistResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.ListWishlistResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for ListWishlistResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __LIST_WISHLIST_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.ListWishlistResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct AddBookToWishlistRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for AddBookToWishlistRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("AddBookToWishlistRequest") + .field("book_id", &self.book_id) + .finish() + } +} +impl AddBookToWishlistRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.AddBookToWishlistRequest"; +} +::buffa::impl_default_instance!(AddBookToWishlistRequest); +impl ::buffa::MessageName for AddBookToWishlistRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "AddBookToWishlistRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.AddBookToWishlistRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.AddBookToWishlistRequest"; +} +impl ::buffa::Message for AddBookToWishlistRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for AddBookToWishlistRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.AddBookToWishlistRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for AddBookToWishlistRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __ADD_BOOK_TO_WISHLIST_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.AddBookToWishlistRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct AddBookToWishlistResponse { + /// Field 1: `added` + #[serde( + rename = "added", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub added: bool, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for AddBookToWishlistResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("AddBookToWishlistResponse").field("added", &self.added).finish() + } +} +impl AddBookToWishlistResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.AddBookToWishlistResponse"; +} +::buffa::impl_default_instance!(AddBookToWishlistResponse); +impl ::buffa::MessageName for AddBookToWishlistResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "AddBookToWishlistResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.AddBookToWishlistResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.AddBookToWishlistResponse"; +} +impl ::buffa::Message for AddBookToWishlistResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.added { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.added { + ::buffa::types::put_bool_field(1u32, self.added, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.added = ::buffa::types::decode_bool(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.added = false; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for AddBookToWishlistResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.AddBookToWishlistResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for AddBookToWishlistResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __ADD_BOOK_TO_WISHLIST_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.AddBookToWishlistResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct RemoveBookFromWishlistRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for RemoveBookFromWishlistRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("RemoveBookFromWishlistRequest") + .field("book_id", &self.book_id) + .finish() + } +} +impl RemoveBookFromWishlistRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RemoveBookFromWishlistRequest"; +} +::buffa::impl_default_instance!(RemoveBookFromWishlistRequest); +impl ::buffa::MessageName for RemoveBookFromWishlistRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "RemoveBookFromWishlistRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.RemoveBookFromWishlistRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RemoveBookFromWishlistRequest"; +} +impl ::buffa::Message for RemoveBookFromWishlistRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for RemoveBookFromWishlistRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.RemoveBookFromWishlistRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for RemoveBookFromWishlistRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __REMOVE_BOOK_FROM_WISHLIST_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.RemoveBookFromWishlistRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct RemoveBookFromWishlistResponse { + /// Field 1: `removed` + #[serde( + rename = "removed", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub removed: bool, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for RemoveBookFromWishlistResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("RemoveBookFromWishlistResponse") + .field("removed", &self.removed) + .finish() + } +} +impl RemoveBookFromWishlistResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RemoveBookFromWishlistResponse"; +} +::buffa::impl_default_instance!(RemoveBookFromWishlistResponse); +impl ::buffa::MessageName for RemoveBookFromWishlistResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "RemoveBookFromWishlistResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.RemoveBookFromWishlistResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RemoveBookFromWishlistResponse"; +} +impl ::buffa::Message for RemoveBookFromWishlistResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.removed { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.removed { + ::buffa::types::put_bool_field(1u32, self.removed, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.removed = ::buffa::types::decode_bool(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.removed = false; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for RemoveBookFromWishlistResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.RemoveBookFromWishlistResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for RemoveBookFromWishlistResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __REMOVE_BOOK_FROM_WISHLIST_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.RemoveBookFromWishlistResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct IsBookInWishlistRequest { + /// Field 1: `book_id` + #[serde( + rename = "bookId", + alias = "book_id", + with = "::buffa::json_helpers::proto_string", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_empty_str" + )] + pub book_id: ::buffa::alloc::string::String, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for IsBookInWishlistRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("IsBookInWishlistRequest") + .field("book_id", &self.book_id) + .finish() + } +} +impl IsBookInWishlistRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.IsBookInWishlistRequest"; +} +::buffa::impl_default_instance!(IsBookInWishlistRequest); +impl ::buffa::MessageName for IsBookInWishlistRequest { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "IsBookInWishlistRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.IsBookInWishlistRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.IsBookInWishlistRequest"; +} +impl ::buffa::Message for IsBookInWishlistRequest { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + ::buffa::types::merge_string(&mut self.book_id, buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.book_id.clear(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for IsBookInWishlistRequest { + const PROTO_FQN: &'static str = "bookbridge.v1.IsBookInWishlistRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for IsBookInWishlistRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __IS_BOOK_IN_WISHLIST_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.IsBookInWishlistRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct IsBookInWishlistResponse { + /// Field 1: `is_favorite` + #[serde( + rename = "isFavorite", + alias = "is_favorite", + with = "::buffa::json_helpers::proto_bool", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_false" + )] + pub is_favorite: bool, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for IsBookInWishlistResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("IsBookInWishlistResponse") + .field("is_favorite", &self.is_favorite) + .finish() + } +} +impl IsBookInWishlistResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.IsBookInWishlistResponse"; +} +::buffa::impl_default_instance!(IsBookInWishlistResponse); +impl ::buffa::MessageName for IsBookInWishlistResponse { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "IsBookInWishlistResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.IsBookInWishlistResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.IsBookInWishlistResponse"; +} +impl ::buffa::Message for IsBookInWishlistResponse { + /// Returns the total encoded size in bytes. + /// + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. + #[allow(clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.is_favorite { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.is_favorite { + ::buffa::types::put_bool_field(1u32, self.is_favorite, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + self.is_favorite = ::buffa::types::decode_bool(buf)?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.is_favorite = false; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for IsBookInWishlistResponse { + const PROTO_FQN: &'static str = "bookbridge.v1.IsBookInWishlistResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for IsBookInWishlistResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __IS_BOOK_IN_WISHLIST_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/bookbridge.v1.IsBookInWishlistResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[allow( + non_camel_case_types, + dead_code, + unused_imports, + unused_qualifications, + clippy::derivable_impls, + clippy::match_single_binding, + clippy::uninlined_format_args, + clippy::doc_lazy_continuation, + clippy::module_inception +)] +pub mod __buffa { + #[allow(unused_imports)] + use super::*; + pub mod view { + #[allow(unused_imports)] + use super::*; + #[derive(Clone, Debug, Default)] + pub struct UserView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `email` + pub email: &'a str, + /// Field 3: `phone` + pub phone: &'a str, + /// Field 4: `first_name` + pub first_name: &'a str, + /// Field 5: `last_name` + pub last_name: &'a str, + /// Field 6: `avatar_url` + pub avatar_url: &'a str, + /// Field 7: `rating` + pub rating: f64, + /// Field 8: `verified` + pub verified: bool, + /// Field 9: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 10: `updated_at` + pub updated_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for UserView<'a> { + type Owned = super::super::User; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.email = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.phone = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.first_name = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.last_name = ::buffa::types::borrow_str(&mut cur)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.avatar_url = ::buffa::types::borrow_str(&mut cur)?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + view.rating = ::buffa::types::decode_double(&mut cur)?; + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.verified = ::buffa::types::decode_bool(&mut cur)?; + } + 9u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.updated_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.updated_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::User { + id: self.id.to_string(), + email: self.email.to_string(), + phone: self.phone.to_string(), + first_name: self.first_name.to_string(), + last_name: self.last_name.to_string(), + avatar_url: self.avatar_url.to_string(), + rating: self.rating, + verified: self.verified, + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + updated_at: match self.updated_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for UserView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.email.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.email) as u64; + } + if !self.phone.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.phone) as u64; + } + if !self.first_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.first_name) + as u64; + } + if !self.last_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.last_name) as u64; + } + if !self.avatar_url.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.avatar_url) + as u64; + } + if self.rating.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + if self.verified { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.updated_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.updated_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.email.is_empty() { + ::buffa::types::put_string_field(2u32, &self.email, buf); + } + if !self.phone.is_empty() { + ::buffa::types::put_string_field(3u32, &self.phone, buf); + } + if !self.first_name.is_empty() { + ::buffa::types::put_string_field(4u32, &self.first_name, buf); + } + if !self.last_name.is_empty() { + ::buffa::types::put_string_field(5u32, &self.last_name, buf); + } + if !self.avatar_url.is_empty() { + ::buffa::types::put_string_field(6u32, &self.avatar_url, buf); + } + if self.rating.to_bits() != 0u64 { + ::buffa::types::put_double_field(7u32, self.rating, buf); + } + if self.verified { + ::buffa::types::put_bool_field(8u32, self.verified, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 9u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + if self.updated_at.is_set() { + ::buffa::types::put_len_delimited_header( + 10u32, + u64::from(__cache.consume_next()), + buf, + ); + self.updated_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for UserView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.email) { + __map.serialize_entry("email", self.email)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.phone) { + __map.serialize_entry("phone", self.phone)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.first_name) { + __map.serialize_entry("firstName", self.first_name)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.last_name) { + __map.serialize_entry("lastName", self.last_name)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.avatar_url) { + __map.serialize_entry("avatarUrl", self.avatar_url)?; + } + if !::buffa::json_helpers::skip_if::is_zero_f64(&self.rating) { + __map + .serialize_entry( + "rating", + &::buffa::json_helpers::ProtoJson(&self.rating), + )?; + } + if self.verified { + __map.serialize_entry("verified", &self.verified)?; + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .updated_at + .as_option() + { + __map.serialize_entry("updatedAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for UserView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "User"; + const FULL_NAME: &'static str = "bookbridge.v1.User"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.User"; + } + ::buffa::impl_default_view_instance!(UserView); + ::buffa::impl_view_reborrow!(UserView); + /** Self-contained, `'static` owned view of a `User` message. + + Wraps [`::buffa::OwnedView`]`<`[`UserView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`UserView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct UserOwnedView(::buffa::OwnedView>); + impl UserOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UserOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UserOwnedView(::buffa::OwnedView::decode_with_options(bytes, opts)?), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::User, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UserOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`UserView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &UserView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::User { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `email` + #[must_use] + pub fn email(&self) -> &'_ str { + self.0.reborrow().email + } + /// Field 3: `phone` + #[must_use] + pub fn phone(&self) -> &'_ str { + self.0.reborrow().phone + } + /// Field 4: `first_name` + #[must_use] + pub fn first_name(&self) -> &'_ str { + self.0.reborrow().first_name + } + /// Field 5: `last_name` + #[must_use] + pub fn last_name(&self) -> &'_ str { + self.0.reborrow().last_name + } + /// Field 6: `avatar_url` + #[must_use] + pub fn avatar_url(&self) -> &'_ str { + self.0.reborrow().avatar_url + } + /// Field 7: `rating` + #[must_use] + pub fn rating(&self) -> f64 { + self.0.reborrow().rating + } + /// Field 8: `verified` + #[must_use] + pub fn verified(&self) -> bool { + self.0.reborrow().verified + } + /// Field 9: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + /// Field 10: `updated_at` + #[must_use] + pub fn updated_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().updated_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for UserOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + UserOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: UserOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for UserOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::User { + type View<'a> = UserView<'a>; + type ViewHandle = UserOwnedView; + } + impl ::serde::Serialize for UserOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SessionView<'a> { + /// Field 1: `session_id` + pub session_id: &'a str, + /// Field 2: `user` + pub user: ::buffa::MessageFieldView< + super::super::__buffa::view::UserView<'a>, + >, + /// Field 3: `access_token` + pub access_token: &'a str, + /// Field 4: `refresh_token` + pub refresh_token: &'a str, + /// Field 5: `access_token_expires_at` + pub access_token_expires_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 6: `expires_at` + pub expires_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SessionView<'a> { + type Owned = super::super::Session; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.session_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.user.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.user = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.access_token = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.refresh_token = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.access_token_expires_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.access_token_expires_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.expires_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.expires_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Session { + session_id: self.session_id.to_string(), + user: match self.user.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::User, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + access_token: self.access_token.to_string(), + refresh_token: self.refresh_token.to_string(), + access_token_expires_at: match self + .access_token_expires_at + .as_option() + { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + expires_at: match self.expires_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SessionView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.session_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.session_id) + as u64; + } + if self.user.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.user.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.access_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.access_token) + as u64; + } + if !self.refresh_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.refresh_token) + as u64; + } + if self.access_token_expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.access_token_expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.session_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.session_id, buf); + } + if self.user.is_set() { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + self.user.write_to(__cache, buf); + } + if !self.access_token.is_empty() { + ::buffa::types::put_string_field(3u32, &self.access_token, buf); + } + if !self.refresh_token.is_empty() { + ::buffa::types::put_string_field(4u32, &self.refresh_token, buf); + } + if self.access_token_expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.access_token_expires_at.write_to(__cache, buf); + } + if self.expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.expires_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SessionView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.session_id) { + __map.serialize_entry("sessionId", self.session_id)?; + } + { + if let ::core::option::Option::Some(__v) = self.user.as_option() { + __map.serialize_entry("user", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.access_token) { + __map.serialize_entry("accessToken", self.access_token)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.refresh_token) { + __map.serialize_entry("refreshToken", self.refresh_token)?; + } + { + if let ::core::option::Option::Some(__v) = self + .access_token_expires_at + .as_option() + { + __map.serialize_entry("accessTokenExpiresAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .expires_at + .as_option() + { + __map.serialize_entry("expiresAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SessionView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Session"; + const FULL_NAME: &'static str = "bookbridge.v1.Session"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Session"; + } + ::buffa::impl_default_view_instance!(SessionView); + ::buffa::impl_view_reborrow!(SessionView); + /** Self-contained, `'static` owned view of a `Session` message. + + Wraps [`::buffa::OwnedView`]`<`[`SessionView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SessionView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SessionOwnedView(::buffa::OwnedView>); + impl SessionOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SessionOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SessionOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Session, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SessionOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SessionView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SessionView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Session { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `session_id` + #[must_use] + pub fn session_id(&self) -> &'_ str { + self.0.reborrow().session_id + } + /// Field 2: `user` + #[must_use] + pub fn user( + &self, + ) -> &::buffa::MessageFieldView> { + &self.0.reborrow().user + } + /// Field 3: `access_token` + #[must_use] + pub fn access_token(&self) -> &'_ str { + self.0.reborrow().access_token + } + /// Field 4: `refresh_token` + #[must_use] + pub fn refresh_token(&self) -> &'_ str { + self.0.reborrow().refresh_token + } + /// Field 5: `access_token_expires_at` + #[must_use] + pub fn access_token_expires_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().access_token_expires_at + } + /// Field 6: `expires_at` + #[must_use] + pub fn expires_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().expires_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SessionOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SessionOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SessionOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SessionOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Session { + type View<'a> = SessionView<'a>; + type ViewHandle = SessionOwnedView; + } + impl ::serde::Serialize for SessionOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SignUpRequestView<'a> { + /// Field 1: `email` + pub email: &'a str, + /// Field 2: `phone` + pub phone: &'a str, + /// Field 3: `password` + pub password: &'a str, + /// Field 4: `first_name` + pub first_name: &'a str, + /// Field 5: `last_name` + pub last_name: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SignUpRequestView<'a> { + type Owned = super::super::SignUpRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.email = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.phone = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.password = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.first_name = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.last_name = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SignUpRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SignUpRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SignUpRequest { + email: self.email.to_string(), + phone: self.phone.to_string(), + password: self.password.to_string(), + first_name: self.first_name.to_string(), + last_name: self.last_name.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SignUpRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.email.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.email) as u64; + } + if !self.phone.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.phone) as u64; + } + if !self.password.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.password) as u64; + } + if !self.first_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.first_name) + as u64; + } + if !self.last_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.last_name) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.email.is_empty() { + ::buffa::types::put_string_field(1u32, &self.email, buf); + } + if !self.phone.is_empty() { + ::buffa::types::put_string_field(2u32, &self.phone, buf); + } + if !self.password.is_empty() { + ::buffa::types::put_string_field(3u32, &self.password, buf); + } + if !self.first_name.is_empty() { + ::buffa::types::put_string_field(4u32, &self.first_name, buf); + } + if !self.last_name.is_empty() { + ::buffa::types::put_string_field(5u32, &self.last_name, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SignUpRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.email) { + __map.serialize_entry("email", self.email)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.phone) { + __map.serialize_entry("phone", self.phone)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.password) { + __map.serialize_entry("password", self.password)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.first_name) { + __map.serialize_entry("firstName", self.first_name)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.last_name) { + __map.serialize_entry("lastName", self.last_name)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SignUpRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignUpRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SignUpRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignUpRequest"; + } + ::buffa::impl_default_view_instance!(SignUpRequestView); + ::buffa::impl_view_reborrow!(SignUpRequestView); + /** Self-contained, `'static` owned view of a `SignUpRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`SignUpRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SignUpRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SignUpRequestOwnedView( + ::buffa::OwnedView>, + ); + impl SignUpRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignUpRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignUpRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SignUpRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignUpRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SignUpRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SignUpRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SignUpRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `email` + #[must_use] + pub fn email(&self) -> &'_ str { + self.0.reborrow().email + } + /// Field 2: `phone` + #[must_use] + pub fn phone(&self) -> &'_ str { + self.0.reborrow().phone + } + /// Field 3: `password` + #[must_use] + pub fn password(&self) -> &'_ str { + self.0.reborrow().password + } + /// Field 4: `first_name` + #[must_use] + pub fn first_name(&self) -> &'_ str { + self.0.reborrow().first_name + } + /// Field 5: `last_name` + #[must_use] + pub fn last_name(&self) -> &'_ str { + self.0.reborrow().last_name + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SignUpRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SignUpRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SignUpRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SignUpRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SignUpRequest { + type View<'a> = SignUpRequestView<'a>; + type ViewHandle = SignUpRequestOwnedView; + } + impl ::serde::Serialize for SignUpRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SignUpResponseView<'a> { + /// Field 1: `session` + pub session: ::buffa::MessageFieldView< + super::super::__buffa::view::SessionView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SignUpResponseView<'a> { + type Owned = super::super::SignUpResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.session.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.session = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SignUpResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SignUpResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SignUpResponse { + session: match self.session.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Session, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SignUpResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.session.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.session.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.session.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.session.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SignUpResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.session.as_option() { + __map.serialize_entry("session", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SignUpResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignUpResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SignUpResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignUpResponse"; + } + ::buffa::impl_default_view_instance!(SignUpResponseView); + ::buffa::impl_view_reborrow!(SignUpResponseView); + /** Self-contained, `'static` owned view of a `SignUpResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`SignUpResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SignUpResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SignUpResponseOwnedView( + ::buffa::OwnedView>, + ); + impl SignUpResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignUpResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignUpResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SignUpResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignUpResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SignUpResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SignUpResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SignUpResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `session` + #[must_use] + pub fn session( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::SessionView<'_>, + > { + &self.0.reborrow().session + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SignUpResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SignUpResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SignUpResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SignUpResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SignUpResponse { + type View<'a> = SignUpResponseView<'a>; + type ViewHandle = SignUpResponseOwnedView; + } + impl ::serde::Serialize for SignUpResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SignInRequestView<'a> { + /// Field 3: `password` + pub password: &'a str, + pub identifier: ::core::option::Option< + super::super::__buffa::view::oneof::sign_in_request::Identifier<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SignInRequestView<'a> { + type Owned = super::super::SignInRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.password = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.identifier = Some( + super::super::__buffa::view::oneof::sign_in_request::Identifier::Email( + ::buffa::types::borrow_str(&mut cur)?, + ), + ); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.identifier = Some( + super::super::__buffa::view::oneof::sign_in_request::Identifier::Phone( + ::buffa::types::borrow_str(&mut cur)?, + ), + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SignInRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SignInRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SignInRequest { + password: self.password.to_string(), + identifier: self + .identifier + .as_ref() + .map(|v| match v { + super::super::__buffa::view::oneof::sign_in_request::Identifier::Email( + v, + ) => { + super::super::__buffa::oneof::sign_in_request::Identifier::Email( + v.to_string(), + ) + } + super::super::__buffa::view::oneof::sign_in_request::Identifier::Phone( + v, + ) => { + super::super::__buffa::oneof::sign_in_request::Identifier::Phone( + v.to_string(), + ) + } + }), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SignInRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if let ::core::option::Option::Some(ref v) = self.identifier { + match v { + super::super::__buffa::view::oneof::sign_in_request::Identifier::Email( + x, + ) => { + size += 1u64 + ::buffa::types::string_encoded_len(x) as u64; + } + super::super::__buffa::view::oneof::sign_in_request::Identifier::Phone( + x, + ) => { + size += 1u64 + ::buffa::types::string_encoded_len(x) as u64; + } + } + } + if !self.password.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.password) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let ::core::option::Option::Some(ref v) = self.identifier { + match v { + super::super::__buffa::view::oneof::sign_in_request::Identifier::Email( + x, + ) => { + ::buffa::types::put_string_field(1u32, x, buf); + } + super::super::__buffa::view::oneof::sign_in_request::Identifier::Phone( + x, + ) => { + ::buffa::types::put_string_field(2u32, x, buf); + } + } + } + if !self.password.is_empty() { + ::buffa::types::put_string_field(3u32, &self.password, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SignInRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.password) { + __map.serialize_entry("password", self.password)?; + } + if let ::core::option::Option::Some(ref __ov) = self.identifier { + match __ov { + super::super::__buffa::view::oneof::sign_in_request::Identifier::Email( + v, + ) => { + __map.serialize_entry("email", v)?; + } + super::super::__buffa::view::oneof::sign_in_request::Identifier::Phone( + v, + ) => { + __map.serialize_entry("phone", v)?; + } + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SignInRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignInRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SignInRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInRequest"; + } + ::buffa::impl_default_view_instance!(SignInRequestView); + ::buffa::impl_view_reborrow!(SignInRequestView); + /** Self-contained, `'static` owned view of a `SignInRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`SignInRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SignInRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SignInRequestOwnedView( + ::buffa::OwnedView>, + ); + impl SignInRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SignInRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SignInRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SignInRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SignInRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 3: `password` + #[must_use] + pub fn password(&self) -> &'_ str { + self.0.reborrow().password + } + /// Oneof `identifier`. + #[must_use] + pub fn identifier( + &self, + ) -> ::core::option::Option< + &super::super::__buffa::view::oneof::sign_in_request::Identifier<'_>, + > { + self.0.reborrow().identifier.as_ref() + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SignInRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SignInRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SignInRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SignInRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SignInRequest { + type View<'a> = SignInRequestView<'a>; + type ViewHandle = SignInRequestOwnedView; + } + impl ::serde::Serialize for SignInRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SignInResponseView<'a> { + /// Field 1: `session` + pub session: ::buffa::MessageFieldView< + super::super::__buffa::view::SessionView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SignInResponseView<'a> { + type Owned = super::super::SignInResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.session.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.session = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SignInResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SignInResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SignInResponse { + session: match self.session.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Session, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SignInResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.session.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.session.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.session.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.session.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SignInResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.session.as_option() { + __map.serialize_entry("session", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SignInResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignInResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SignInResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInResponse"; + } + ::buffa::impl_default_view_instance!(SignInResponseView); + ::buffa::impl_view_reborrow!(SignInResponseView); + /** Self-contained, `'static` owned view of a `SignInResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`SignInResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SignInResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SignInResponseOwnedView( + ::buffa::OwnedView>, + ); + impl SignInResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SignInResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SignInResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SignInResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SignInResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `session` + #[must_use] + pub fn session( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::SessionView<'_>, + > { + &self.0.reborrow().session + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SignInResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SignInResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SignInResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SignInResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SignInResponse { + type View<'a> = SignInResponseView<'a>; + type ViewHandle = SignInResponseOwnedView; + } + impl ::serde::Serialize for SignInResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SignInWithGoogleRequestView<'a> { + /// Field 1: `id_token` + pub id_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SignInWithGoogleRequestView<'a> { + type Owned = super::super::SignInWithGoogleRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id_token = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SignInWithGoogleRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SignInWithGoogleRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SignInWithGoogleRequest { + id_token: self.id_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SignInWithGoogleRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.id_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SignInWithGoogleRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id_token) { + __map.serialize_entry("idToken", self.id_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SignInWithGoogleRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignInWithGoogleRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SignInWithGoogleRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInWithGoogleRequest"; + } + ::buffa::impl_default_view_instance!(SignInWithGoogleRequestView); + ::buffa::impl_view_reborrow!(SignInWithGoogleRequestView); + /** Self-contained, `'static` owned view of a `SignInWithGoogleRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`SignInWithGoogleRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SignInWithGoogleRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SignInWithGoogleRequestOwnedView( + ::buffa::OwnedView>, + ); + impl SignInWithGoogleRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInWithGoogleRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInWithGoogleRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SignInWithGoogleRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInWithGoogleRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`SignInWithGoogleRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SignInWithGoogleRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SignInWithGoogleRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id_token` + #[must_use] + pub fn id_token(&self) -> &'_ str { + self.0.reborrow().id_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for SignInWithGoogleRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + SignInWithGoogleRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SignInWithGoogleRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for SignInWithGoogleRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SignInWithGoogleRequest { + type View<'a> = SignInWithGoogleRequestView<'a>; + type ViewHandle = SignInWithGoogleRequestOwnedView; + } + impl ::serde::Serialize for SignInWithGoogleRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SignInWithGoogleResponseView<'a> { + /// Field 1: `session` + pub session: ::buffa::MessageFieldView< + super::super::__buffa::view::SessionView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SignInWithGoogleResponseView<'a> { + type Owned = super::super::SignInWithGoogleResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.session.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.session = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SignInWithGoogleResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SignInWithGoogleResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SignInWithGoogleResponse { + session: match self.session.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Session, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SignInWithGoogleResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.session.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.session.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.session.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.session.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SignInWithGoogleResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.session.as_option() { + __map.serialize_entry("session", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SignInWithGoogleResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignInWithGoogleResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SignInWithGoogleResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignInWithGoogleResponse"; + } + ::buffa::impl_default_view_instance!(SignInWithGoogleResponseView); + ::buffa::impl_view_reborrow!(SignInWithGoogleResponseView); + /** Self-contained, `'static` owned view of a `SignInWithGoogleResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`SignInWithGoogleResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SignInWithGoogleResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SignInWithGoogleResponseOwnedView( + ::buffa::OwnedView>, + ); + impl SignInWithGoogleResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInWithGoogleResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInWithGoogleResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SignInWithGoogleResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignInWithGoogleResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`SignInWithGoogleResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SignInWithGoogleResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SignInWithGoogleResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `session` + #[must_use] + pub fn session( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::SessionView<'_>, + > { + &self.0.reborrow().session + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for SignInWithGoogleResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + SignInWithGoogleResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SignInWithGoogleResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for SignInWithGoogleResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SignInWithGoogleResponse { + type View<'a> = SignInWithGoogleResponseView<'a>; + type ViewHandle = SignInWithGoogleResponseOwnedView; + } + impl ::serde::Serialize for SignInWithGoogleResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct RefreshSessionRequestView<'a> { + /// The opaque refresh token issued with the current session. + /// + /// Field 1: `refresh_token` + pub refresh_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for RefreshSessionRequestView<'a> { + type Owned = super::super::RefreshSessionRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.refresh_token = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::RefreshSessionRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::RefreshSessionRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::RefreshSessionRequest { + refresh_token: self.refresh_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for RefreshSessionRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.refresh_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.refresh_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.refresh_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.refresh_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for RefreshSessionRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.refresh_token) { + __map.serialize_entry("refreshToken", self.refresh_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for RefreshSessionRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "RefreshSessionRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.RefreshSessionRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RefreshSessionRequest"; + } + ::buffa::impl_default_view_instance!(RefreshSessionRequestView); + ::buffa::impl_view_reborrow!(RefreshSessionRequestView); + /** Self-contained, `'static` owned view of a `RefreshSessionRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`RefreshSessionRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`RefreshSessionRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct RefreshSessionRequestOwnedView( + ::buffa::OwnedView>, + ); + impl RefreshSessionRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RefreshSessionRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RefreshSessionRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::RefreshSessionRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RefreshSessionRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`RefreshSessionRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &RefreshSessionRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::RefreshSessionRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// The opaque refresh token issued with the current session. + /// + /// Field 1: `refresh_token` + #[must_use] + pub fn refresh_token(&self) -> &'_ str { + self.0.reborrow().refresh_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for RefreshSessionRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + RefreshSessionRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: RefreshSessionRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for RefreshSessionRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::RefreshSessionRequest { + type View<'a> = RefreshSessionRequestView<'a>; + type ViewHandle = RefreshSessionRequestOwnedView; + } + impl ::serde::Serialize for RefreshSessionRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct RefreshSessionResponseView<'a> { + /// New session with a fresh access token and a rotated refresh token; + /// the presented refresh token is invalidated. + /// + /// Field 1: `session` + pub session: ::buffa::MessageFieldView< + super::super::__buffa::view::SessionView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for RefreshSessionResponseView<'a> { + type Owned = super::super::RefreshSessionResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.session.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.session = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::RefreshSessionResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::RefreshSessionResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::RefreshSessionResponse { + session: match self.session.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Session, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for RefreshSessionResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.session.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.session.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.session.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.session.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for RefreshSessionResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.session.as_option() { + __map.serialize_entry("session", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for RefreshSessionResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "RefreshSessionResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.RefreshSessionResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RefreshSessionResponse"; + } + ::buffa::impl_default_view_instance!(RefreshSessionResponseView); + ::buffa::impl_view_reborrow!(RefreshSessionResponseView); + /** Self-contained, `'static` owned view of a `RefreshSessionResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`RefreshSessionResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`RefreshSessionResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct RefreshSessionResponseOwnedView( + ::buffa::OwnedView>, + ); + impl RefreshSessionResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RefreshSessionResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RefreshSessionResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::RefreshSessionResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RefreshSessionResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`RefreshSessionResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &RefreshSessionResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::RefreshSessionResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// New session with a fresh access token and a rotated refresh token; + /// the presented refresh token is invalidated. + /// + /// Field 1: `session` + #[must_use] + pub fn session( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::SessionView<'_>, + > { + &self.0.reborrow().session + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for RefreshSessionResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + RefreshSessionResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: RefreshSessionResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for RefreshSessionResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::RefreshSessionResponse { + type View<'a> = RefreshSessionResponseView<'a>; + type ViewHandle = RefreshSessionResponseOwnedView; + } + impl ::serde::Serialize for RefreshSessionResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SignOutRequestView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SignOutRequestView<'a> { + type Owned = super::super::SignOutRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SignOutRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SignOutRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SignOutRequest { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SignOutRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SignOutRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for SignOutRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignOutRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SignOutRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignOutRequest"; + } + ::buffa::impl_default_view_instance!(SignOutRequestView); + ::buffa::impl_view_reborrow!(SignOutRequestView); + /** Self-contained, `'static` owned view of a `SignOutRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`SignOutRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SignOutRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SignOutRequestOwnedView( + ::buffa::OwnedView>, + ); + impl SignOutRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignOutRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignOutRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SignOutRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignOutRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SignOutRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SignOutRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SignOutRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SignOutRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SignOutRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SignOutRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SignOutRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SignOutRequest { + type View<'a> = SignOutRequestView<'a>; + type ViewHandle = SignOutRequestOwnedView; + } + impl ::serde::Serialize for SignOutRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SignOutResponseView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SignOutResponseView<'a> { + type Owned = super::super::SignOutResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SignOutResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SignOutResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SignOutResponse { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SignOutResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SignOutResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for SignOutResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SignOutResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SignOutResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SignOutResponse"; + } + ::buffa::impl_default_view_instance!(SignOutResponseView); + ::buffa::impl_view_reborrow!(SignOutResponseView); + /** Self-contained, `'static` owned view of a `SignOutResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`SignOutResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SignOutResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SignOutResponseOwnedView( + ::buffa::OwnedView>, + ); + impl SignOutResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignOutResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignOutResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SignOutResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SignOutResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SignOutResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SignOutResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SignOutResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SignOutResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SignOutResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SignOutResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SignOutResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SignOutResponse { + type View<'a> = SignOutResponseView<'a>; + type ViewHandle = SignOutResponseOwnedView; + } + impl ::serde::Serialize for SignOutResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetCurrentUserRequestView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetCurrentUserRequestView<'a> { + type Owned = super::super::GetCurrentUserRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetCurrentUserRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetCurrentUserRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetCurrentUserRequest { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetCurrentUserRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetCurrentUserRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetCurrentUserRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetCurrentUserRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetCurrentUserRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetCurrentUserRequest"; + } + ::buffa::impl_default_view_instance!(GetCurrentUserRequestView); + ::buffa::impl_view_reborrow!(GetCurrentUserRequestView); + /** Self-contained, `'static` owned view of a `GetCurrentUserRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetCurrentUserRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetCurrentUserRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetCurrentUserRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetCurrentUserRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetCurrentUserRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetCurrentUserRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetCurrentUserRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetCurrentUserRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetCurrentUserRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetCurrentUserRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetCurrentUserRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetCurrentUserRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetCurrentUserRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetCurrentUserRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetCurrentUserRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetCurrentUserRequest { + type View<'a> = GetCurrentUserRequestView<'a>; + type ViewHandle = GetCurrentUserRequestOwnedView; + } + impl ::serde::Serialize for GetCurrentUserRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetCurrentUserResponseView<'a> { + /// Field 1: `user` + pub user: ::buffa::MessageFieldView< + super::super::__buffa::view::UserView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetCurrentUserResponseView<'a> { + type Owned = super::super::GetCurrentUserResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.user.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.user = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetCurrentUserResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetCurrentUserResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetCurrentUserResponse { + user: match self.user.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::User, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetCurrentUserResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.user.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.user.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.user.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.user.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetCurrentUserResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.user.as_option() { + __map.serialize_entry("user", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetCurrentUserResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetCurrentUserResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetCurrentUserResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetCurrentUserResponse"; + } + ::buffa::impl_default_view_instance!(GetCurrentUserResponseView); + ::buffa::impl_view_reborrow!(GetCurrentUserResponseView); + /** Self-contained, `'static` owned view of a `GetCurrentUserResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetCurrentUserResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetCurrentUserResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetCurrentUserResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetCurrentUserResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetCurrentUserResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetCurrentUserResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetCurrentUserResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetCurrentUserResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetCurrentUserResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetCurrentUserResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetCurrentUserResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `user` + #[must_use] + pub fn user( + &self, + ) -> &::buffa::MessageFieldView> { + &self.0.reborrow().user + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetCurrentUserResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetCurrentUserResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetCurrentUserResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetCurrentUserResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetCurrentUserResponse { + type View<'a> = GetCurrentUserResponseView<'a>; + type ViewHandle = GetCurrentUserResponseOwnedView; + } + impl ::serde::Serialize for GetCurrentUserResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct UpdateCurrentUserRequestView<'a> { + /// Field 1: `email` + pub email: ::core::option::Option<&'a str>, + /// Field 2: `first_name` + pub first_name: ::core::option::Option<&'a str>, + /// Field 3: `last_name` + pub last_name: ::core::option::Option<&'a str>, + /// Field 4: `avatar_upload_id` + pub avatar_upload_id: ::core::option::Option<&'a str>, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for UpdateCurrentUserRequestView<'a> { + type Owned = super::super::UpdateCurrentUserRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.email = Some(::buffa::types::borrow_str(&mut cur)?); + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.first_name = Some(::buffa::types::borrow_str(&mut cur)?); + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.last_name = Some(::buffa::types::borrow_str(&mut cur)?); + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.avatar_upload_id = Some( + ::buffa::types::borrow_str(&mut cur)?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::UpdateCurrentUserRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::UpdateCurrentUserRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::UpdateCurrentUserRequest { + email: self.email.map(|s| s.to_string()), + first_name: self.first_name.map(|s| s.to_string()), + last_name: self.last_name.map(|s| s.to_string()), + avatar_upload_id: self.avatar_upload_id.map(|s| s.to_string()), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for UpdateCurrentUserRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if let Some(ref v) = self.email { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(ref v) = self.first_name { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(ref v) = self.last_name { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(ref v) = self.avatar_upload_id { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let Some(ref v) = self.email { + ::buffa::types::put_string_field(1u32, v, buf); + } + if let Some(ref v) = self.first_name { + ::buffa::types::put_string_field(2u32, v, buf); + } + if let Some(ref v) = self.last_name { + ::buffa::types::put_string_field(3u32, v, buf); + } + if let Some(ref v) = self.avatar_upload_id { + ::buffa::types::put_string_field(4u32, v, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for UpdateCurrentUserRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if let ::core::option::Option::Some(__v) = self.email { + __map.serialize_entry("email", __v)?; + } + if let ::core::option::Option::Some(__v) = self.first_name { + __map.serialize_entry("firstName", __v)?; + } + if let ::core::option::Option::Some(__v) = self.last_name { + __map.serialize_entry("lastName", __v)?; + } + if let ::core::option::Option::Some(__v) = self.avatar_upload_id { + __map.serialize_entry("avatarUploadId", __v)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for UpdateCurrentUserRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UpdateCurrentUserRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.UpdateCurrentUserRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateCurrentUserRequest"; + } + ::buffa::impl_default_view_instance!(UpdateCurrentUserRequestView); + ::buffa::impl_view_reborrow!(UpdateCurrentUserRequestView); + /** Self-contained, `'static` owned view of a `UpdateCurrentUserRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`UpdateCurrentUserRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`UpdateCurrentUserRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct UpdateCurrentUserRequestOwnedView( + ::buffa::OwnedView>, + ); + impl UpdateCurrentUserRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateCurrentUserRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateCurrentUserRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::UpdateCurrentUserRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateCurrentUserRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`UpdateCurrentUserRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &UpdateCurrentUserRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UpdateCurrentUserRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `email` + #[must_use] + pub fn email(&self) -> ::core::option::Option<&'_ str> { + self.0.reborrow().email + } + /// Field 2: `first_name` + #[must_use] + pub fn first_name(&self) -> ::core::option::Option<&'_ str> { + self.0.reborrow().first_name + } + /// Field 3: `last_name` + #[must_use] + pub fn last_name(&self) -> ::core::option::Option<&'_ str> { + self.0.reborrow().last_name + } + /// Field 4: `avatar_upload_id` + #[must_use] + pub fn avatar_upload_id(&self) -> ::core::option::Option<&'_ str> { + self.0.reborrow().avatar_upload_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for UpdateCurrentUserRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + UpdateCurrentUserRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: UpdateCurrentUserRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for UpdateCurrentUserRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::UpdateCurrentUserRequest { + type View<'a> = UpdateCurrentUserRequestView<'a>; + type ViewHandle = UpdateCurrentUserRequestOwnedView; + } + impl ::serde::Serialize for UpdateCurrentUserRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct UpdateCurrentUserResponseView<'a> { + /// Field 1: `user` + pub user: ::buffa::MessageFieldView< + super::super::__buffa::view::UserView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for UpdateCurrentUserResponseView<'a> { + type Owned = super::super::UpdateCurrentUserResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.user.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.user = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::UpdateCurrentUserResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::UpdateCurrentUserResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::UpdateCurrentUserResponse { + user: match self.user.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::User, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for UpdateCurrentUserResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.user.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.user.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.user.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.user.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for UpdateCurrentUserResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.user.as_option() { + __map.serialize_entry("user", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for UpdateCurrentUserResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UpdateCurrentUserResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.UpdateCurrentUserResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateCurrentUserResponse"; + } + ::buffa::impl_default_view_instance!(UpdateCurrentUserResponseView); + ::buffa::impl_view_reborrow!(UpdateCurrentUserResponseView); + /** Self-contained, `'static` owned view of a `UpdateCurrentUserResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`UpdateCurrentUserResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`UpdateCurrentUserResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct UpdateCurrentUserResponseOwnedView( + ::buffa::OwnedView>, + ); + impl UpdateCurrentUserResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateCurrentUserResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateCurrentUserResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::UpdateCurrentUserResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateCurrentUserResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`UpdateCurrentUserResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &UpdateCurrentUserResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UpdateCurrentUserResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `user` + #[must_use] + pub fn user( + &self, + ) -> &::buffa::MessageFieldView> { + &self.0.reborrow().user + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for UpdateCurrentUserResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + UpdateCurrentUserResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: UpdateCurrentUserResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for UpdateCurrentUserResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::UpdateCurrentUserResponse { + type View<'a> = UpdateCurrentUserResponseView<'a>; + type ViewHandle = UpdateCurrentUserResponseOwnedView; + } + impl ::serde::Serialize for UpdateCurrentUserResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SendPasswordResetRequestView<'a> { + /// Field 1: `email` + pub email: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SendPasswordResetRequestView<'a> { + type Owned = super::super::SendPasswordResetRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.email = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SendPasswordResetRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SendPasswordResetRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SendPasswordResetRequest { + email: self.email.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SendPasswordResetRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.email.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.email) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.email.is_empty() { + ::buffa::types::put_string_field(1u32, &self.email, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SendPasswordResetRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.email) { + __map.serialize_entry("email", self.email)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SendPasswordResetRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SendPasswordResetRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SendPasswordResetRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendPasswordResetRequest"; + } + ::buffa::impl_default_view_instance!(SendPasswordResetRequestView); + ::buffa::impl_view_reborrow!(SendPasswordResetRequestView); + /** Self-contained, `'static` owned view of a `SendPasswordResetRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`SendPasswordResetRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SendPasswordResetRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SendPasswordResetRequestOwnedView( + ::buffa::OwnedView>, + ); + impl SendPasswordResetRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendPasswordResetRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendPasswordResetRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SendPasswordResetRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendPasswordResetRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`SendPasswordResetRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SendPasswordResetRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SendPasswordResetRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `email` + #[must_use] + pub fn email(&self) -> &'_ str { + self.0.reborrow().email + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for SendPasswordResetRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + SendPasswordResetRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SendPasswordResetRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for SendPasswordResetRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SendPasswordResetRequest { + type View<'a> = SendPasswordResetRequestView<'a>; + type ViewHandle = SendPasswordResetRequestOwnedView; + } + impl ::serde::Serialize for SendPasswordResetRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SendPasswordResetResponseView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SendPasswordResetResponseView<'a> { + type Owned = super::super::SendPasswordResetResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SendPasswordResetResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SendPasswordResetResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SendPasswordResetResponse { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SendPasswordResetResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SendPasswordResetResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for SendPasswordResetResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SendPasswordResetResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SendPasswordResetResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendPasswordResetResponse"; + } + ::buffa::impl_default_view_instance!(SendPasswordResetResponseView); + ::buffa::impl_view_reborrow!(SendPasswordResetResponseView); + /** Self-contained, `'static` owned view of a `SendPasswordResetResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`SendPasswordResetResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SendPasswordResetResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SendPasswordResetResponseOwnedView( + ::buffa::OwnedView>, + ); + impl SendPasswordResetResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendPasswordResetResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendPasswordResetResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SendPasswordResetResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendPasswordResetResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`SendPasswordResetResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SendPasswordResetResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SendPasswordResetResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for SendPasswordResetResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + SendPasswordResetResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SendPasswordResetResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for SendPasswordResetResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SendPasswordResetResponse { + type View<'a> = SendPasswordResetResponseView<'a>; + type ViewHandle = SendPasswordResetResponseOwnedView; + } + impl ::serde::Serialize for SendPasswordResetResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Registers/updates the FCM token of the device tied to the current session + /// (maps to user_sessions.fcm_token). + #[derive(Clone, Debug, Default)] + pub struct SetDeviceTokenRequestView<'a> { + /// Field 1: `fcm_token` + pub fcm_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SetDeviceTokenRequestView<'a> { + type Owned = super::super::SetDeviceTokenRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.fcm_token = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SetDeviceTokenRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SetDeviceTokenRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SetDeviceTokenRequest { + fcm_token: self.fcm_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SetDeviceTokenRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.fcm_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.fcm_token) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.fcm_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.fcm_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SetDeviceTokenRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.fcm_token) { + __map.serialize_entry("fcmToken", self.fcm_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SetDeviceTokenRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SetDeviceTokenRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SetDeviceTokenRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SetDeviceTokenRequest"; + } + ::buffa::impl_default_view_instance!(SetDeviceTokenRequestView); + ::buffa::impl_view_reborrow!(SetDeviceTokenRequestView); + /** Self-contained, `'static` owned view of a `SetDeviceTokenRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`SetDeviceTokenRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SetDeviceTokenRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SetDeviceTokenRequestOwnedView( + ::buffa::OwnedView>, + ); + impl SetDeviceTokenRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SetDeviceTokenRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SetDeviceTokenRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SetDeviceTokenRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SetDeviceTokenRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SetDeviceTokenRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SetDeviceTokenRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SetDeviceTokenRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `fcm_token` + #[must_use] + pub fn fcm_token(&self) -> &'_ str { + self.0.reborrow().fcm_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for SetDeviceTokenRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + SetDeviceTokenRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SetDeviceTokenRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for SetDeviceTokenRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SetDeviceTokenRequest { + type View<'a> = SetDeviceTokenRequestView<'a>; + type ViewHandle = SetDeviceTokenRequestOwnedView; + } + impl ::serde::Serialize for SetDeviceTokenRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SetDeviceTokenResponseView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SetDeviceTokenResponseView<'a> { + type Owned = super::super::SetDeviceTokenResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SetDeviceTokenResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SetDeviceTokenResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SetDeviceTokenResponse { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SetDeviceTokenResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SetDeviceTokenResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for SetDeviceTokenResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SetDeviceTokenResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SetDeviceTokenResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SetDeviceTokenResponse"; + } + ::buffa::impl_default_view_instance!(SetDeviceTokenResponseView); + ::buffa::impl_view_reborrow!(SetDeviceTokenResponseView); + /** Self-contained, `'static` owned view of a `SetDeviceTokenResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`SetDeviceTokenResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SetDeviceTokenResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SetDeviceTokenResponseOwnedView( + ::buffa::OwnedView>, + ); + impl SetDeviceTokenResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SetDeviceTokenResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SetDeviceTokenResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SetDeviceTokenResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SetDeviceTokenResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SetDeviceTokenResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SetDeviceTokenResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SetDeviceTokenResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for SetDeviceTokenResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + SetDeviceTokenResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SetDeviceTokenResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for SetDeviceTokenResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SetDeviceTokenResponse { + type View<'a> = SetDeviceTokenResponseView<'a>; + type ViewHandle = SetDeviceTokenResponseOwnedView; + } + impl ::serde::Serialize for SetDeviceTokenResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct LatLngView<'a> { + /// Field 1: `latitude` + pub latitude: f64, + /// Field 2: `longitude` + pub longitude: f64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for LatLngView<'a> { + type Owned = super::super::LatLng; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + view.latitude = ::buffa::types::decode_double(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + view.longitude = ::buffa::types::decode_double(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::LatLng { + latitude: self.latitude, + longitude: self.longitude, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for LatLngView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.latitude.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + if self.longitude.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.latitude.to_bits() != 0u64 { + ::buffa::types::put_double_field(1u32, self.latitude, buf); + } + if self.longitude.to_bits() != 0u64 { + ::buffa::types::put_double_field(2u32, self.longitude, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for LatLngView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_zero_f64(&self.latitude) { + __map + .serialize_entry( + "latitude", + &::buffa::json_helpers::ProtoJson(&self.latitude), + )?; + } + if !::buffa::json_helpers::skip_if::is_zero_f64(&self.longitude) { + __map + .serialize_entry( + "longitude", + &::buffa::json_helpers::ProtoJson(&self.longitude), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for LatLngView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "LatLng"; + const FULL_NAME: &'static str = "bookbridge.v1.LatLng"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.LatLng"; + } + ::buffa::impl_default_view_instance!(LatLngView); + ::buffa::impl_view_reborrow!(LatLngView); + /** Self-contained, `'static` owned view of a `LatLng` message. + + Wraps [`::buffa::OwnedView`]`<`[`LatLngView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`LatLngView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct LatLngOwnedView(::buffa::OwnedView>); + impl LatLngOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + LatLngOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + LatLngOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::LatLng, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + LatLngOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`LatLngView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &LatLngView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::LatLng { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `latitude` + #[must_use] + pub fn latitude(&self) -> f64 { + self.0.reborrow().latitude + } + /// Field 2: `longitude` + #[must_use] + pub fn longitude(&self) -> f64 { + self.0.reborrow().longitude + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for LatLngOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + LatLngOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: LatLngOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for LatLngOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::LatLng { + type View<'a> = LatLngView<'a>; + type ViewHandle = LatLngOwnedView; + } + impl ::serde::Serialize for LatLngOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Public-facing user info embedded in books, conversations, reviews, etc. + #[derive(Clone, Debug, Default)] + pub struct UserSummaryView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `first_name` + pub first_name: &'a str, + /// Field 3: `last_name` + pub last_name: &'a str, + /// Field 4: `avatar_url` + pub avatar_url: &'a str, + /// Field 5: `rating` + pub rating: f64, + /// Field 6: `verified` + pub verified: bool, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for UserSummaryView<'a> { + type Owned = super::super::UserSummary; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.first_name = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.last_name = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.avatar_url = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + view.rating = ::buffa::types::decode_double(&mut cur)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.verified = ::buffa::types::decode_bool(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::UserSummary, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::UserSummary, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::UserSummary { + id: self.id.to_string(), + first_name: self.first_name.to_string(), + last_name: self.last_name.to_string(), + avatar_url: self.avatar_url.to_string(), + rating: self.rating, + verified: self.verified, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for UserSummaryView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.first_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.first_name) + as u64; + } + if !self.last_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.last_name) as u64; + } + if !self.avatar_url.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.avatar_url) + as u64; + } + if self.rating.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + if self.verified { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.first_name.is_empty() { + ::buffa::types::put_string_field(2u32, &self.first_name, buf); + } + if !self.last_name.is_empty() { + ::buffa::types::put_string_field(3u32, &self.last_name, buf); + } + if !self.avatar_url.is_empty() { + ::buffa::types::put_string_field(4u32, &self.avatar_url, buf); + } + if self.rating.to_bits() != 0u64 { + ::buffa::types::put_double_field(5u32, self.rating, buf); + } + if self.verified { + ::buffa::types::put_bool_field(6u32, self.verified, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for UserSummaryView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.first_name) { + __map.serialize_entry("firstName", self.first_name)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.last_name) { + __map.serialize_entry("lastName", self.last_name)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.avatar_url) { + __map.serialize_entry("avatarUrl", self.avatar_url)?; + } + if !::buffa::json_helpers::skip_if::is_zero_f64(&self.rating) { + __map + .serialize_entry( + "rating", + &::buffa::json_helpers::ProtoJson(&self.rating), + )?; + } + if self.verified { + __map.serialize_entry("verified", &self.verified)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for UserSummaryView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UserSummary"; + const FULL_NAME: &'static str = "bookbridge.v1.UserSummary"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UserSummary"; + } + ::buffa::impl_default_view_instance!(UserSummaryView); + ::buffa::impl_view_reborrow!(UserSummaryView); + /** Self-contained, `'static` owned view of a `UserSummary` message. + + Wraps [`::buffa::OwnedView`]`<`[`UserSummaryView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`UserSummaryView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct UserSummaryOwnedView(::buffa::OwnedView>); + impl UserSummaryOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UserSummaryOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UserSummaryOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::UserSummary, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UserSummaryOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`UserSummaryView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &UserSummaryView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UserSummary { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `first_name` + #[must_use] + pub fn first_name(&self) -> &'_ str { + self.0.reborrow().first_name + } + /// Field 3: `last_name` + #[must_use] + pub fn last_name(&self) -> &'_ str { + self.0.reborrow().last_name + } + /// Field 4: `avatar_url` + #[must_use] + pub fn avatar_url(&self) -> &'_ str { + self.0.reborrow().avatar_url + } + /// Field 5: `rating` + #[must_use] + pub fn rating(&self) -> f64 { + self.0.reborrow().rating + } + /// Field 6: `verified` + #[must_use] + pub fn verified(&self) -> bool { + self.0.reborrow().verified + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for UserSummaryOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + UserSummaryOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: UserSummaryOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for UserSummaryOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::UserSummary { + type View<'a> = UserSummaryView<'a>; + type ViewHandle = UserSummaryOwnedView; + } + impl ::serde::Serialize for UserSummaryOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct BookCategoryView<'a> { + /// Field 1: `id` + pub id: i64, + /// Field 2: `name` + pub name: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for BookCategoryView<'a> { + type Owned = super::super::BookCategory; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.id = ::buffa::types::decode_int64(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.name = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::BookCategory, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::BookCategory, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::BookCategory { + id: self.id, + name: self.name.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for BookCategoryView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.id != 0i64 { + size += 1u64 + ::buffa::types::int64_encoded_len(self.id) as u64; + } + if !self.name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.name) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.id != 0i64 { + ::buffa::types::put_int64_field(1u32, self.id, buf); + } + if !self.name.is_empty() { + ::buffa::types::put_string_field(2u32, &self.name, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for BookCategoryView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.id) { + __map + .serialize_entry( + "id", + &::buffa::json_helpers::ProtoJson(&self.id), + )?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.name) { + __map.serialize_entry("name", self.name)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for BookCategoryView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "BookCategory"; + const FULL_NAME: &'static str = "bookbridge.v1.BookCategory"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookCategory"; + } + ::buffa::impl_default_view_instance!(BookCategoryView); + ::buffa::impl_view_reborrow!(BookCategoryView); + /** Self-contained, `'static` owned view of a `BookCategory` message. + + Wraps [`::buffa::OwnedView`]`<`[`BookCategoryView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`BookCategoryView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct BookCategoryOwnedView(::buffa::OwnedView>); + impl BookCategoryOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookCategoryOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookCategoryOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::BookCategory, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookCategoryOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`BookCategoryView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &BookCategoryView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::BookCategory { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> i64 { + self.0.reborrow().id + } + /// Field 2: `name` + #[must_use] + pub fn name(&self) -> &'_ str { + self.0.reborrow().name + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for BookCategoryOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + BookCategoryOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: BookCategoryOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for BookCategoryOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::BookCategory { + type View<'a> = BookCategoryView<'a>; + type ViewHandle = BookCategoryOwnedView; + } + impl ::serde::Serialize for BookCategoryOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct BookPictureView<'a> { + /// Field 1: `upload_id` + pub upload_id: &'a str, + /// Field 2: `url` + pub url: &'a str, + /// Field 3: `type` + pub r#type: ::buffa::EnumValue, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for BookPictureView<'a> { + type Owned = super::super::BookPicture; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.upload_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.url = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.r#type = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::BookPicture, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::BookPicture, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::BookPicture { + upload_id: self.upload_id.to_string(), + url: self.url.to_string(), + r#type: self.r#type, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for BookPictureView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + if !self.url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.url) as u64; + } + { + let val = self.r#type.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + if !self.url.is_empty() { + ::buffa::types::put_string_field(2u32, &self.url, buf); + } + { + let val = self.r#type.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(3u32, val, buf); + } + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for BookPictureView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.upload_id) { + __map.serialize_entry("uploadId", self.upload_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.url) { + __map.serialize_entry("url", self.url)?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.r#type) { + __map.serialize_entry("type", &self.r#type)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for BookPictureView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "BookPicture"; + const FULL_NAME: &'static str = "bookbridge.v1.BookPicture"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookPicture"; + } + ::buffa::impl_default_view_instance!(BookPictureView); + ::buffa::impl_view_reborrow!(BookPictureView); + /** Self-contained, `'static` owned view of a `BookPicture` message. + + Wraps [`::buffa::OwnedView`]`<`[`BookPictureView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`BookPictureView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct BookPictureOwnedView(::buffa::OwnedView>); + impl BookPictureOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookPictureOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookPictureOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::BookPicture, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookPictureOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`BookPictureView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &BookPictureView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::BookPicture { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `upload_id` + #[must_use] + pub fn upload_id(&self) -> &'_ str { + self.0.reborrow().upload_id + } + /// Field 2: `url` + #[must_use] + pub fn url(&self) -> &'_ str { + self.0.reborrow().url + } + /// Field 3: `type` + #[must_use] + pub fn r#type(&self) -> ::buffa::EnumValue { + self.0.reborrow().r#type + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for BookPictureOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + BookPictureOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: BookPictureOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for BookPictureOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::BookPicture { + type View<'a> = BookPictureView<'a>; + type ViewHandle = BookPictureOwnedView; + } + impl ::serde::Serialize for BookPictureOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to the books table with its seller joined in. + #[derive(Clone, Debug, Default)] + pub struct BookView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `seller` + pub seller: ::buffa::MessageFieldView< + super::super::__buffa::view::UserSummaryView<'a>, + >, + /// Field 3: `title` + pub title: &'a str, + /// Field 4: `author` + pub author: &'a str, + /// Field 5: `price_fcfa` + pub price_fcfa: i64, + /// Field 6: `condition` + pub condition: ::buffa::EnumValue, + /// Field 7: `description` + pub description: &'a str, + /// Field 8: `status` + pub status: ::buffa::EnumValue, + /// Field 9: `category` + pub category: ::buffa::MessageFieldView< + super::super::__buffa::view::BookCategoryView<'a>, + >, + /// Field 10: `refundable` + pub refundable: bool, + /// Field 11: `swapable` + pub swapable: bool, + /// Field 12: `pictures` + pub pictures: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::BookPictureView<'a>, + >, + /// Field 13: `ebook_id` + pub ebook_id: &'a str, + /// Field 14: `boost_expires_at` + pub boost_expires_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 15: `expires_at` + pub expires_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 16: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 17: `updated_at` + pub updated_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 18: `location` + pub location: ::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for BookView<'a> { + type Owned = super::super::Book; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.seller.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.seller = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.title = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.author = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.price_fcfa = ::buffa::types::decode_int64(&mut cur)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.condition = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.description = ::buffa::types::borrow_str(&mut cur)?; + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 9u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.category.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.category = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.refundable = ::buffa::types::decode_bool(&mut cur)?; + } + 11u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.swapable = ::buffa::types::decode_bool(&mut cur)?; + } + 13u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.ebook_id = ::buffa::types::borrow_str(&mut cur)?; + } + 14u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.boost_expires_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.boost_expires_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 15u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.expires_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.expires_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 16u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 17u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.updated_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.updated_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 18u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.location.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.location = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 12u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::BookPictureView, + >(), + )?; + view.pictures + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Book { + id: self.id.to_string(), + seller: match self.seller.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::UserSummary, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + title: self.title.to_string(), + author: self.author.to_string(), + price_fcfa: self.price_fcfa, + condition: self.condition, + description: self.description.to_string(), + status: self.status, + category: match self.category.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::BookCategory, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + refundable: self.refundable, + swapable: self.swapable, + pictures: self + .pictures + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + ebook_id: self.ebook_id.to_string(), + boost_expires_at: match self.boost_expires_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + expires_at: match self.expires_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + updated_at: match self.updated_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + location: match self.location.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::LatLng, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for BookView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if self.seller.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.seller.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.title.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.author.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.author) as u64; + } + if self.price_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.price_fcfa) as u64; + } + { + let val = self.condition.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if !self.description.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.description) + as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.category.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.category.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.refundable { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.swapable { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + for v in &self.pictures { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.ebook_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.ebook_id) as u64; + } + if self.boost_expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.boost_expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 2u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.updated_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.updated_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 2u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 2u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if self.seller.is_set() { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + self.seller.write_to(__cache, buf); + } + if !self.title.is_empty() { + ::buffa::types::put_string_field(3u32, &self.title, buf); + } + if !self.author.is_empty() { + ::buffa::types::put_string_field(4u32, &self.author, buf); + } + if self.price_fcfa != 0i64 { + ::buffa::types::put_int64_field(5u32, self.price_fcfa, buf); + } + { + let val = self.condition.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(6u32, val, buf); + } + } + if !self.description.is_empty() { + ::buffa::types::put_string_field(7u32, &self.description, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(8u32, val, buf); + } + } + if self.category.is_set() { + ::buffa::types::put_len_delimited_header( + 9u32, + u64::from(__cache.consume_next()), + buf, + ); + self.category.write_to(__cache, buf); + } + if self.refundable { + ::buffa::types::put_bool_field(10u32, self.refundable, buf); + } + if self.swapable { + ::buffa::types::put_bool_field(11u32, self.swapable, buf); + } + for v in &self.pictures { + ::buffa::types::put_len_delimited_header( + 12u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.ebook_id.is_empty() { + ::buffa::types::put_string_field(13u32, &self.ebook_id, buf); + } + if self.boost_expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 14u32, + u64::from(__cache.consume_next()), + buf, + ); + self.boost_expires_at.write_to(__cache, buf); + } + if self.expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 15u32, + u64::from(__cache.consume_next()), + buf, + ); + self.expires_at.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 16u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + if self.updated_at.is_set() { + ::buffa::types::put_len_delimited_header( + 17u32, + u64::from(__cache.consume_next()), + buf, + ); + self.updated_at.write_to(__cache, buf); + } + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 18u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for BookView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + { + if let ::core::option::Option::Some(__v) = self.seller.as_option() { + __map.serialize_entry("seller", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.title) { + __map.serialize_entry("title", self.title)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.author) { + __map.serialize_entry("author", self.author)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.price_fcfa) { + __map + .serialize_entry( + "priceFcfa", + &::buffa::json_helpers::ProtoJson(&self.price_fcfa), + )?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value( + &self.condition, + ) { + __map.serialize_entry("condition", &self.condition)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.description) { + __map.serialize_entry("description", self.description)?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.status) { + __map.serialize_entry("status", &self.status)?; + } + { + if let ::core::option::Option::Some(__v) = self.category.as_option() + { + __map.serialize_entry("category", __v)?; + } + } + if self.refundable { + __map.serialize_entry("refundable", &self.refundable)?; + } + if self.swapable { + __map.serialize_entry("swapable", &self.swapable)?; + } + if !self.pictures.is_empty() { + __map.serialize_entry("pictures", &*self.pictures)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.ebook_id) { + __map.serialize_entry("ebookId", self.ebook_id)?; + } + { + if let ::core::option::Option::Some(__v) = self + .boost_expires_at + .as_option() + { + __map.serialize_entry("boostExpiresAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .expires_at + .as_option() + { + __map.serialize_entry("expiresAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .updated_at + .as_option() + { + __map.serialize_entry("updatedAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self.location.as_option() + { + __map.serialize_entry("location", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for BookView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Book"; + const FULL_NAME: &'static str = "bookbridge.v1.Book"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Book"; + } + ::buffa::impl_default_view_instance!(BookView); + ::buffa::impl_view_reborrow!(BookView); + /** Self-contained, `'static` owned view of a `Book` message. + + Wraps [`::buffa::OwnedView`]`<`[`BookView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`BookView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct BookOwnedView(::buffa::OwnedView>); + impl BookOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookOwnedView(::buffa::OwnedView::decode_with_options(bytes, opts)?), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Book, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`BookView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &BookView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Book { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `seller` + #[must_use] + pub fn seller( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::UserSummaryView<'_>, + > { + &self.0.reborrow().seller + } + /// Field 3: `title` + #[must_use] + pub fn title(&self) -> &'_ str { + self.0.reborrow().title + } + /// Field 4: `author` + #[must_use] + pub fn author(&self) -> &'_ str { + self.0.reborrow().author + } + /// Field 5: `price_fcfa` + #[must_use] + pub fn price_fcfa(&self) -> i64 { + self.0.reborrow().price_fcfa + } + /// Field 6: `condition` + #[must_use] + pub fn condition(&self) -> ::buffa::EnumValue { + self.0.reborrow().condition + } + /// Field 7: `description` + #[must_use] + pub fn description(&self) -> &'_ str { + self.0.reborrow().description + } + /// Field 8: `status` + #[must_use] + pub fn status(&self) -> ::buffa::EnumValue { + self.0.reborrow().status + } + /// Field 9: `category` + #[must_use] + pub fn category( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::BookCategoryView<'_>, + > { + &self.0.reborrow().category + } + /// Field 10: `refundable` + #[must_use] + pub fn refundable(&self) -> bool { + self.0.reborrow().refundable + } + /// Field 11: `swapable` + #[must_use] + pub fn swapable(&self) -> bool { + self.0.reborrow().swapable + } + /// Field 12: `pictures` + #[must_use] + pub fn pictures( + &self, + ) -> &::buffa::RepeatedView< + '_, + super::super::__buffa::view::BookPictureView<'_>, + > { + &self.0.reborrow().pictures + } + /// Field 13: `ebook_id` + #[must_use] + pub fn ebook_id(&self) -> &'_ str { + self.0.reborrow().ebook_id + } + /// Field 14: `boost_expires_at` + #[must_use] + pub fn boost_expires_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().boost_expires_at + } + /// Field 15: `expires_at` + #[must_use] + pub fn expires_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().expires_at + } + /// Field 16: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + /// Field 17: `updated_at` + #[must_use] + pub fn updated_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().updated_at + } + /// Field 18: `location` + #[must_use] + pub fn location( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'_>, + > { + &self.0.reborrow().location + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for BookOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + BookOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: BookOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for BookOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Book { + type View<'a> = BookView<'a>; + type ViewHandle = BookOwnedView; + } + impl ::serde::Serialize for BookOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListCategoriesRequestView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListCategoriesRequestView<'a> { + type Owned = super::super::ListCategoriesRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListCategoriesRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListCategoriesRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListCategoriesRequest { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListCategoriesRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListCategoriesRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListCategoriesRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListCategoriesRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListCategoriesRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListCategoriesRequest"; + } + ::buffa::impl_default_view_instance!(ListCategoriesRequestView); + ::buffa::impl_view_reborrow!(ListCategoriesRequestView); + /** Self-contained, `'static` owned view of a `ListCategoriesRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListCategoriesRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListCategoriesRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListCategoriesRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListCategoriesRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListCategoriesRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListCategoriesRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListCategoriesRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListCategoriesRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListCategoriesRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListCategoriesRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListCategoriesRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListCategoriesRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListCategoriesRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListCategoriesRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListCategoriesRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListCategoriesRequest { + type View<'a> = ListCategoriesRequestView<'a>; + type ViewHandle = ListCategoriesRequestOwnedView; + } + impl ::serde::Serialize for ListCategoriesRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListCategoriesResponseView<'a> { + /// Field 1: `categories` + pub categories: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::BookCategoryView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListCategoriesResponseView<'a> { + type Owned = super::super::ListCategoriesResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::BookCategoryView, + >(), + )?; + view.categories + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListCategoriesResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListCategoriesResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListCategoriesResponse { + categories: self + .categories + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListCategoriesResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.categories { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.categories { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListCategoriesResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.categories.is_empty() { + __map.serialize_entry("categories", &*self.categories)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListCategoriesResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListCategoriesResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListCategoriesResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListCategoriesResponse"; + } + ::buffa::impl_default_view_instance!(ListCategoriesResponseView); + ::buffa::impl_view_reborrow!(ListCategoriesResponseView); + /** Self-contained, `'static` owned view of a `ListCategoriesResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListCategoriesResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListCategoriesResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListCategoriesResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListCategoriesResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListCategoriesResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListCategoriesResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListCategoriesResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListCategoriesResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListCategoriesResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListCategoriesResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListCategoriesResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `categories` + #[must_use] + pub fn categories( + &self, + ) -> &::buffa::RepeatedView< + '_, + super::super::__buffa::view::BookCategoryView<'_>, + > { + &self.0.reborrow().categories + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListCategoriesResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListCategoriesResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListCategoriesResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListCategoriesResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListCategoriesResponse { + type View<'a> = ListCategoriesResponseView<'a>; + type ViewHandle = ListCategoriesResponseOwnedView; + } + impl ::serde::Serialize for ListCategoriesResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListBooksRequestView<'a> { + /// Field 1: `page_token` + pub page_token: &'a str, + /// Field 2: `page_size` + pub page_size: i32, + /// Field 3: `status` + pub status: ::buffa::EnumValue, + /// Field 4: `category_id` + pub category_id: i64, + /// Center for radius-based discovery (uses the indexed_locations H3 columns). + /// + /// Field 5: `center` + pub center: ::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'a>, + >, + /// Field 6: `radius_km` + pub radius_km: f64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListBooksRequestView<'a> { + type Owned = super::super::ListBooksRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.category_id = ::buffa::types::decode_int64(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.center.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.center = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + view.radius_km = ::buffa::types::decode_double(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListBooksRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListBooksRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListBooksRequest { + page_token: self.page_token.to_string(), + page_size: self.page_size, + status: self.status, + category_id: self.category_id, + center: match self.center.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::LatLng, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + radius_km: self.radius_km, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListBooksRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.category_id != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.category_id) as u64; + } + if self.center.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.center.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.radius_km.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(3u32, val, buf); + } + } + if self.category_id != 0i64 { + ::buffa::types::put_int64_field(4u32, self.category_id, buf); + } + if self.center.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.center.write_to(__cache, buf); + } + if self.radius_km.to_bits() != 0u64 { + ::buffa::types::put_double_field(6u32, self.radius_km, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListBooksRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.status) { + __map.serialize_entry("status", &self.status)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.category_id) { + __map + .serialize_entry( + "categoryId", + &::buffa::json_helpers::ProtoJson(&self.category_id), + )?; + } + { + if let ::core::option::Option::Some(__v) = self.center.as_option() { + __map.serialize_entry("center", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_zero_f64(&self.radius_km) { + __map + .serialize_entry( + "radiusKm", + &::buffa::json_helpers::ProtoJson(&self.radius_km), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListBooksRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListBooksRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListBooksRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksRequest"; + } + ::buffa::impl_default_view_instance!(ListBooksRequestView); + ::buffa::impl_view_reborrow!(ListBooksRequestView); + /** Self-contained, `'static` owned view of a `ListBooksRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListBooksRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListBooksRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListBooksRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListBooksRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListBooksRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListBooksRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListBooksRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListBooksRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 2: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + /// Field 3: `status` + #[must_use] + pub fn status(&self) -> ::buffa::EnumValue { + self.0.reborrow().status + } + /// Field 4: `category_id` + #[must_use] + pub fn category_id(&self) -> i64 { + self.0.reborrow().category_id + } + /// Center for radius-based discovery (uses the indexed_locations H3 columns). + /// + /// Field 5: `center` + #[must_use] + pub fn center( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'_>, + > { + &self.0.reborrow().center + } + /// Field 6: `radius_km` + #[must_use] + pub fn radius_km(&self) -> f64 { + self.0.reborrow().radius_km + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListBooksRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + ListBooksRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListBooksRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ListBooksRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListBooksRequest { + type View<'a> = ListBooksRequestView<'a>; + type ViewHandle = ListBooksRequestOwnedView; + } + impl ::serde::Serialize for ListBooksRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListBooksResponseView<'a> { + /// Field 1: `books` + pub books: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::BookView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListBooksResponseView<'a> { + type Owned = super::super::ListBooksResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::BookView, + >(), + )?; + view.books + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListBooksResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListBooksResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListBooksResponse { + books: self + .books + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListBooksResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListBooksResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.books.is_empty() { + __map.serialize_entry("books", &*self.books)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListBooksResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListBooksResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListBooksResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksResponse"; + } + ::buffa::impl_default_view_instance!(ListBooksResponseView); + ::buffa::impl_view_reborrow!(ListBooksResponseView); + /** Self-contained, `'static` owned view of a `ListBooksResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListBooksResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListBooksResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListBooksResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListBooksResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListBooksResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListBooksResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListBooksResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListBooksResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `books` + #[must_use] + pub fn books( + &self, + ) -> &::buffa::RepeatedView<'_, super::super::__buffa::view::BookView<'_>> { + &self.0.reborrow().books + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListBooksResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + ListBooksResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListBooksResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ListBooksResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListBooksResponse { + type View<'a> = ListBooksResponseView<'a>; + type ViewHandle = ListBooksResponseOwnedView; + } + impl ::serde::Serialize for ListBooksResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SearchBooksRequestView<'a> { + /// Field 1: `query` + pub query: &'a str, + /// Field 2: `page_token` + pub page_token: &'a str, + /// Field 3: `page_size` + pub page_size: i32, + /// Field 4: `category_id` + pub category_id: i64, + /// Field 5: `center` + pub center: ::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'a>, + >, + /// Field 6: `radius_km` + pub radius_km: f64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SearchBooksRequestView<'a> { + type Owned = super::super::SearchBooksRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.query = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.category_id = ::buffa::types::decode_int64(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.center.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.center = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + view.radius_km = ::buffa::types::decode_double(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SearchBooksRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SearchBooksRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SearchBooksRequest { + query: self.query.to_string(), + page_token: self.page_token.to_string(), + page_size: self.page_size, + category_id: self.category_id, + center: match self.center.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::LatLng, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + radius_km: self.radius_km, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SearchBooksRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.query.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.query) as u64; + } + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + if self.category_id != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.category_id) as u64; + } + if self.center.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.center.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.radius_km.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.query.is_empty() { + ::buffa::types::put_string_field(1u32, &self.query, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(3u32, self.page_size, buf); + } + if self.category_id != 0i64 { + ::buffa::types::put_int64_field(4u32, self.category_id, buf); + } + if self.center.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.center.write_to(__cache, buf); + } + if self.radius_km.to_bits() != 0u64 { + ::buffa::types::put_double_field(6u32, self.radius_km, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SearchBooksRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.query) { + __map.serialize_entry("query", self.query)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.category_id) { + __map + .serialize_entry( + "categoryId", + &::buffa::json_helpers::ProtoJson(&self.category_id), + )?; + } + { + if let ::core::option::Option::Some(__v) = self.center.as_option() { + __map.serialize_entry("center", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_zero_f64(&self.radius_km) { + __map + .serialize_entry( + "radiusKm", + &::buffa::json_helpers::ProtoJson(&self.radius_km), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SearchBooksRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SearchBooksRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SearchBooksRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SearchBooksRequest"; + } + ::buffa::impl_default_view_instance!(SearchBooksRequestView); + ::buffa::impl_view_reborrow!(SearchBooksRequestView); + /** Self-contained, `'static` owned view of a `SearchBooksRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`SearchBooksRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SearchBooksRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SearchBooksRequestOwnedView( + ::buffa::OwnedView>, + ); + impl SearchBooksRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SearchBooksRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SearchBooksRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SearchBooksRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SearchBooksRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SearchBooksRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SearchBooksRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SearchBooksRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `query` + #[must_use] + pub fn query(&self) -> &'_ str { + self.0.reborrow().query + } + /// Field 2: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 3: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + /// Field 4: `category_id` + #[must_use] + pub fn category_id(&self) -> i64 { + self.0.reborrow().category_id + } + /// Field 5: `center` + #[must_use] + pub fn center( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'_>, + > { + &self.0.reborrow().center + } + /// Field 6: `radius_km` + #[must_use] + pub fn radius_km(&self) -> f64 { + self.0.reborrow().radius_km + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SearchBooksRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SearchBooksRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SearchBooksRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SearchBooksRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SearchBooksRequest { + type View<'a> = SearchBooksRequestView<'a>; + type ViewHandle = SearchBooksRequestOwnedView; + } + impl ::serde::Serialize for SearchBooksRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SearchBooksResponseView<'a> { + /// Field 1: `books` + pub books: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::BookView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SearchBooksResponseView<'a> { + type Owned = super::super::SearchBooksResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::BookView, + >(), + )?; + view.books + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SearchBooksResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SearchBooksResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SearchBooksResponse { + books: self + .books + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SearchBooksResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SearchBooksResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.books.is_empty() { + __map.serialize_entry("books", &*self.books)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SearchBooksResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SearchBooksResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SearchBooksResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SearchBooksResponse"; + } + ::buffa::impl_default_view_instance!(SearchBooksResponseView); + ::buffa::impl_view_reborrow!(SearchBooksResponseView); + /** Self-contained, `'static` owned view of a `SearchBooksResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`SearchBooksResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SearchBooksResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SearchBooksResponseOwnedView( + ::buffa::OwnedView>, + ); + impl SearchBooksResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SearchBooksResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SearchBooksResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SearchBooksResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SearchBooksResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SearchBooksResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SearchBooksResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SearchBooksResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `books` + #[must_use] + pub fn books( + &self, + ) -> &::buffa::RepeatedView<'_, super::super::__buffa::view::BookView<'_>> { + &self.0.reborrow().books + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SearchBooksResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + SearchBooksResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SearchBooksResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SearchBooksResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SearchBooksResponse { + type View<'a> = SearchBooksResponseView<'a>; + type ViewHandle = SearchBooksResponseOwnedView; + } + impl ::serde::Serialize for SearchBooksResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetBookRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetBookRequestView<'a> { + type Owned = super::super::GetBookRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetBookRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetBookRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetBookRequest { + book_id: self.book_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetBookRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetBookRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetBookRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetBookRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetBookRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBookRequest"; + } + ::buffa::impl_default_view_instance!(GetBookRequestView); + ::buffa::impl_view_reborrow!(GetBookRequestView); + /** Self-contained, `'static` owned view of a `GetBookRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetBookRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetBookRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetBookRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetBookRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBookRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBookRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetBookRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBookRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetBookRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetBookRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetBookRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GetBookRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + GetBookRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetBookRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GetBookRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetBookRequest { + type View<'a> = GetBookRequestView<'a>; + type ViewHandle = GetBookRequestOwnedView; + } + impl ::serde::Serialize for GetBookRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetBookResponseView<'a> { + /// Field 1: `book` + pub book: ::buffa::MessageFieldView< + super::super::__buffa::view::BookView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetBookResponseView<'a> { + type Owned = super::super::GetBookResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.book.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.book = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetBookResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetBookResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetBookResponse { + book: match self.book.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Book, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetBookResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetBookResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.book.as_option() { + __map.serialize_entry("book", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetBookResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetBookResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetBookResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBookResponse"; + } + ::buffa::impl_default_view_instance!(GetBookResponseView); + ::buffa::impl_view_reborrow!(GetBookResponseView); + /** Self-contained, `'static` owned view of a `GetBookResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetBookResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetBookResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetBookResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetBookResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBookResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBookResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetBookResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBookResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetBookResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetBookResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetBookResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book` + #[must_use] + pub fn book( + &self, + ) -> &::buffa::MessageFieldView> { + &self.0.reborrow().book + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GetBookResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + GetBookResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetBookResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GetBookResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetBookResponse { + type View<'a> = GetBookResponseView<'a>; + type ViewHandle = GetBookResponseOwnedView; + } + impl ::serde::Serialize for GetBookResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListBooksBySellerRequestView<'a> { + /// Field 1: `seller_id` + pub seller_id: &'a str, + /// Field 2: `page_token` + pub page_token: &'a str, + /// Field 3: `page_size` + pub page_size: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListBooksBySellerRequestView<'a> { + type Owned = super::super::ListBooksBySellerRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.seller_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListBooksBySellerRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListBooksBySellerRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListBooksBySellerRequest { + seller_id: self.seller_id.to_string(), + page_token: self.page_token.to_string(), + page_size: self.page_size, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListBooksBySellerRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.seller_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.seller_id) as u64; + } + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.seller_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.seller_id, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(3u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListBooksBySellerRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.seller_id) { + __map.serialize_entry("sellerId", self.seller_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListBooksBySellerRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListBooksBySellerRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListBooksBySellerRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksBySellerRequest"; + } + ::buffa::impl_default_view_instance!(ListBooksBySellerRequestView); + ::buffa::impl_view_reborrow!(ListBooksBySellerRequestView); + /** Self-contained, `'static` owned view of a `ListBooksBySellerRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListBooksBySellerRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListBooksBySellerRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListBooksBySellerRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListBooksBySellerRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksBySellerRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksBySellerRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListBooksBySellerRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksBySellerRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListBooksBySellerRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListBooksBySellerRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListBooksBySellerRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `seller_id` + #[must_use] + pub fn seller_id(&self) -> &'_ str { + self.0.reborrow().seller_id + } + /// Field 2: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 3: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListBooksBySellerRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListBooksBySellerRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListBooksBySellerRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListBooksBySellerRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListBooksBySellerRequest { + type View<'a> = ListBooksBySellerRequestView<'a>; + type ViewHandle = ListBooksBySellerRequestOwnedView; + } + impl ::serde::Serialize for ListBooksBySellerRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListBooksBySellerResponseView<'a> { + /// Field 1: `books` + pub books: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::BookView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListBooksBySellerResponseView<'a> { + type Owned = super::super::ListBooksBySellerResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::BookView, + >(), + )?; + view.books + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListBooksBySellerResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListBooksBySellerResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListBooksBySellerResponse { + books: self + .books + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListBooksBySellerResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListBooksBySellerResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.books.is_empty() { + __map.serialize_entry("books", &*self.books)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListBooksBySellerResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListBooksBySellerResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListBooksBySellerResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListBooksBySellerResponse"; + } + ::buffa::impl_default_view_instance!(ListBooksBySellerResponseView); + ::buffa::impl_view_reborrow!(ListBooksBySellerResponseView); + /** Self-contained, `'static` owned view of a `ListBooksBySellerResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListBooksBySellerResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListBooksBySellerResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListBooksBySellerResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListBooksBySellerResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksBySellerResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksBySellerResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListBooksBySellerResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListBooksBySellerResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListBooksBySellerResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListBooksBySellerResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListBooksBySellerResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `books` + #[must_use] + pub fn books( + &self, + ) -> &::buffa::RepeatedView<'_, super::super::__buffa::view::BookView<'_>> { + &self.0.reborrow().books + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListBooksBySellerResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListBooksBySellerResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListBooksBySellerResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListBooksBySellerResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListBooksBySellerResponse { + type View<'a> = ListBooksBySellerResponseView<'a>; + type ViewHandle = ListBooksBySellerResponseOwnedView; + } + impl ::serde::Serialize for ListBooksBySellerResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMyBooksRequestView<'a> { + /// Field 1: `page_token` + pub page_token: &'a str, + /// Field 2: `page_size` + pub page_size: i32, + /// Field 3: `status` + pub status: ::buffa::EnumValue, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMyBooksRequestView<'a> { + type Owned = super::super::ListMyBooksRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMyBooksRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMyBooksRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMyBooksRequest { + page_token: self.page_token.to_string(), + page_size: self.page_size, + status: self.status, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMyBooksRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(3u32, val, buf); + } + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMyBooksRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.status) { + __map.serialize_entry("status", &self.status)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMyBooksRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMyBooksRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMyBooksRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyBooksRequest"; + } + ::buffa::impl_default_view_instance!(ListMyBooksRequestView); + ::buffa::impl_view_reborrow!(ListMyBooksRequestView); + /** Self-contained, `'static` owned view of a `ListMyBooksRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMyBooksRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMyBooksRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMyBooksRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListMyBooksRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyBooksRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyBooksRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMyBooksRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyBooksRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListMyBooksRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMyBooksRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMyBooksRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 2: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + /// Field 3: `status` + #[must_use] + pub fn status(&self) -> ::buffa::EnumValue { + self.0.reborrow().status + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListMyBooksRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + ListMyBooksRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMyBooksRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ListMyBooksRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMyBooksRequest { + type View<'a> = ListMyBooksRequestView<'a>; + type ViewHandle = ListMyBooksRequestOwnedView; + } + impl ::serde::Serialize for ListMyBooksRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMyBooksResponseView<'a> { + /// Field 1: `books` + pub books: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::BookView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMyBooksResponseView<'a> { + type Owned = super::super::ListMyBooksResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::BookView, + >(), + )?; + view.books + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMyBooksResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMyBooksResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMyBooksResponse { + books: self + .books + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMyBooksResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMyBooksResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.books.is_empty() { + __map.serialize_entry("books", &*self.books)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMyBooksResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMyBooksResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMyBooksResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyBooksResponse"; + } + ::buffa::impl_default_view_instance!(ListMyBooksResponseView); + ::buffa::impl_view_reborrow!(ListMyBooksResponseView); + /** Self-contained, `'static` owned view of a `ListMyBooksResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMyBooksResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMyBooksResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMyBooksResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListMyBooksResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyBooksResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyBooksResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMyBooksResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyBooksResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListMyBooksResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMyBooksResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMyBooksResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `books` + #[must_use] + pub fn books( + &self, + ) -> &::buffa::RepeatedView<'_, super::super::__buffa::view::BookView<'_>> { + &self.0.reborrow().books + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListMyBooksResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListMyBooksResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMyBooksResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ListMyBooksResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMyBooksResponse { + type View<'a> = ListMyBooksResponseView<'a>; + type ViewHandle = ListMyBooksResponseOwnedView; + } + impl ::serde::Serialize for ListMyBooksResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateBookRequestView<'a> { + /// Field 1: `title` + pub title: &'a str, + /// Field 2: `author` + pub author: &'a str, + /// Field 3: `price_fcfa` + pub price_fcfa: i64, + /// Field 4: `condition` + pub condition: ::buffa::EnumValue, + /// Field 5: `description` + pub description: &'a str, + /// Field 6: `category_id` + pub category_id: i64, + /// Field 7: `refundable` + pub refundable: bool, + /// Field 8: `swapable` + pub swapable: bool, + /// Field 9: `picture_upload_ids` + pub picture_upload_ids: ::buffa::RepeatedView<'a, &'a str>, + /// Field 10: `picture_types` (map) + pub picture_types: ::buffa::MapView< + 'a, + &'a str, + ::buffa::EnumValue, + >, + /// Field 11: `ebook_upload_id` + pub ebook_upload_id: &'a str, + /// Field 12: `location` + pub location: ::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'a>, + >, + /// Listing expiry in days from creation; server assigns a default when unset. + /// + /// Field 13: `expires_in_days` + pub expires_in_days: ::core::option::Option, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateBookRequestView<'a> { + type Owned = super::super::CreateBookRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.title = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.author = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.price_fcfa = ::buffa::types::decode_int64(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.condition = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.description = ::buffa::types::borrow_str(&mut cur)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.category_id = ::buffa::types::decode_int64(&mut cur)?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.refundable = ::buffa::types::decode_bool(&mut cur)?; + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.swapable = ::buffa::types::decode_bool(&mut cur)?; + } + 11u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.ebook_upload_id = ::buffa::types::borrow_str(&mut cur)?; + } + 12u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.location.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.location = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 13u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.expires_in_days = Some( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 9u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __elem = ::buffa::types::borrow_str(&mut cur)?; + ctx.register_element_memory( + ::buffa::__private::element_footprint(&__elem), + )?; + view.picture_upload_ids.push(__elem); + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let entry_bytes = ::buffa::types::borrow_bytes(&mut cur)?; + let mut entry_cur: &'a [u8] = entry_bytes; + let mut key = ""; + let mut val = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&key) + + ::buffa::__private::element_footprint(&val), + )?; + while !entry_cur.is_empty() { + let entry_tag = ::buffa::encoding::Tag::decode( + &mut entry_cur, + )?; + match entry_tag.field_number() { + 1 => { + ::buffa::encoding::check_wire_type( + entry_tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + key = ::buffa::types::borrow_str(&mut entry_cur)?; + } + 2 => { + ::buffa::encoding::check_wire_type( + entry_tag, + ::buffa::encoding::WireType::Varint, + )?; + val = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut entry_cur)?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth( + entry_tag, + &mut entry_cur, + ctx.depth(), + )?; + } + } + } + view.picture_types.push(key, val); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateBookRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateBookRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateBookRequest { + title: self.title.to_string(), + author: self.author.to_string(), + price_fcfa: self.price_fcfa, + condition: self.condition, + description: self.description.to_string(), + category_id: self.category_id, + refundable: self.refundable, + swapable: self.swapable, + picture_upload_ids: self + .picture_upload_ids + .iter() + .map(|s| s.to_string()) + .collect(), + picture_types: self + .picture_types + .iter() + .map(|(k, v)| (k.to_string(), *v)) + .collect(), + ebook_upload_id: self.ebook_upload_id.to_string(), + location: match self.location.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::LatLng, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + expires_in_days: self.expires_in_days, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateBookRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.title.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.author.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.author) as u64; + } + if self.price_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.price_fcfa) as u64; + } + { + let val = self.condition.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if !self.description.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.description) + as u64; + } + if self.category_id != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.category_id) as u64; + } + if self.refundable { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.swapable { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + for v in &self.picture_upload_ids { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + #[allow(clippy::for_kv_map)] + for (k, v) in &self.picture_types { + let entry_size: u64 = 1u64 + + ::buffa::types::string_encoded_len(k) as u64 + 1u64 + + ::buffa::types::int32_encoded_len(v.to_i32()) as u64; + size + += 1u64 + ::buffa::encoding::varint_len(entry_size) as u64 + + entry_size; + } + if !self.ebook_upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.ebook_upload_id) + as u64; + } + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if let Some(v) = self.expires_in_days { + size += 1u64 + ::buffa::types::int32_encoded_len(v) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.title.is_empty() { + ::buffa::types::put_string_field(1u32, &self.title, buf); + } + if !self.author.is_empty() { + ::buffa::types::put_string_field(2u32, &self.author, buf); + } + if self.price_fcfa != 0i64 { + ::buffa::types::put_int64_field(3u32, self.price_fcfa, buf); + } + { + let val = self.condition.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(4u32, val, buf); + } + } + if !self.description.is_empty() { + ::buffa::types::put_string_field(5u32, &self.description, buf); + } + if self.category_id != 0i64 { + ::buffa::types::put_int64_field(6u32, self.category_id, buf); + } + if self.refundable { + ::buffa::types::put_bool_field(7u32, self.refundable, buf); + } + if self.swapable { + ::buffa::types::put_bool_field(8u32, self.swapable, buf); + } + for v in &self.picture_upload_ids { + ::buffa::types::put_string_field(9u32, v, buf); + } + for (k, v) in &self.picture_types { + let entry_size: u64 = 1u64 + + ::buffa::types::string_encoded_len(k) as u64 + 1u64 + + ::buffa::types::int32_encoded_len(v.to_i32()) as u64; + ::buffa::encoding::Tag::new( + 10u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(entry_size, buf); + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::types::encode_string(k, buf); + ::buffa::encoding::Tag::new( + 2u32, + ::buffa::encoding::WireType::Varint, + ) + .encode(buf); + ::buffa::types::encode_int32(v.to_i32(), buf); + } + if !self.ebook_upload_id.is_empty() { + ::buffa::types::put_string_field(11u32, &self.ebook_upload_id, buf); + } + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 12u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + if let Some(v) = self.expires_in_days { + ::buffa::types::put_int32_field(13u32, v, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateBookRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.title) { + __map.serialize_entry("title", self.title)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.author) { + __map.serialize_entry("author", self.author)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.price_fcfa) { + __map + .serialize_entry( + "priceFcfa", + &::buffa::json_helpers::ProtoJson(&self.price_fcfa), + )?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value( + &self.condition, + ) { + __map.serialize_entry("condition", &self.condition)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.description) { + __map.serialize_entry("description", self.description)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.category_id) { + __map + .serialize_entry( + "categoryId", + &::buffa::json_helpers::ProtoJson(&self.category_id), + )?; + } + if self.refundable { + __map.serialize_entry("refundable", &self.refundable)?; + } + if self.swapable { + __map.serialize_entry("swapable", &self.swapable)?; + } + if !self.picture_upload_ids.is_empty() { + __map + .serialize_entry("pictureUploadIds", &*self.picture_upload_ids)?; + } + if !self.picture_types.is_empty() { + struct _WM<'__a, '__x>( + &'__x ::buffa::MapView< + '__x, + &'__a str, + ::buffa::EnumValue, + >, + ); + impl<'__a> ::serde::Serialize for _WM<'__a, '_> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __m = __s + .serialize_map(::core::option::Option::Some(self.0.len()))?; + for (k, v) in self.0.iter_unique() { + __m.serialize_entry(k, v)?; + } + __m.end() + } + } + __map.serialize_entry("pictureTypes", &_WM(&self.picture_types))?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.ebook_upload_id) { + __map.serialize_entry("ebookUploadId", self.ebook_upload_id)?; + } + { + if let ::core::option::Option::Some(__v) = self.location.as_option() + { + __map.serialize_entry("location", __v)?; + } + } + if let ::core::option::Option::Some(__v) = self.expires_in_days { + __map + .serialize_entry( + "expiresInDays", + &::buffa::json_helpers::ProtoJson(&__v), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateBookRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBookRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBookRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookRequest"; + } + ::buffa::impl_default_view_instance!(CreateBookRequestView); + ::buffa::impl_view_reborrow!(CreateBookRequestView); + /** Self-contained, `'static` owned view of a `CreateBookRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateBookRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateBookRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateBookRequestOwnedView( + ::buffa::OwnedView>, + ); + impl CreateBookRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateBookRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateBookRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateBookRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateBookRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `title` + #[must_use] + pub fn title(&self) -> &'_ str { + self.0.reborrow().title + } + /// Field 2: `author` + #[must_use] + pub fn author(&self) -> &'_ str { + self.0.reborrow().author + } + /// Field 3: `price_fcfa` + #[must_use] + pub fn price_fcfa(&self) -> i64 { + self.0.reborrow().price_fcfa + } + /// Field 4: `condition` + #[must_use] + pub fn condition(&self) -> ::buffa::EnumValue { + self.0.reborrow().condition + } + /// Field 5: `description` + #[must_use] + pub fn description(&self) -> &'_ str { + self.0.reborrow().description + } + /// Field 6: `category_id` + #[must_use] + pub fn category_id(&self) -> i64 { + self.0.reborrow().category_id + } + /// Field 7: `refundable` + #[must_use] + pub fn refundable(&self) -> bool { + self.0.reborrow().refundable + } + /// Field 8: `swapable` + #[must_use] + pub fn swapable(&self) -> bool { + self.0.reborrow().swapable + } + /// Field 9: `picture_upload_ids` + #[must_use] + pub fn picture_upload_ids(&self) -> &::buffa::RepeatedView<'_, &'_ str> { + &self.0.reborrow().picture_upload_ids + } + /// Field 10: `picture_types` (map) + #[must_use] + pub fn picture_types( + &self, + ) -> &::buffa::MapView< + '_, + &'_ str, + ::buffa::EnumValue, + > { + &self.0.reborrow().picture_types + } + /// Field 11: `ebook_upload_id` + #[must_use] + pub fn ebook_upload_id(&self) -> &'_ str { + self.0.reborrow().ebook_upload_id + } + /// Field 12: `location` + #[must_use] + pub fn location( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'_>, + > { + &self.0.reborrow().location + } + /// Listing expiry in days from creation; server assigns a default when unset. + /// + /// Field 13: `expires_in_days` + #[must_use] + pub fn expires_in_days(&self) -> ::core::option::Option { + self.0.reborrow().expires_in_days + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for CreateBookRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + CreateBookRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateBookRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for CreateBookRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateBookRequest { + type View<'a> = CreateBookRequestView<'a>; + type ViewHandle = CreateBookRequestOwnedView; + } + impl ::serde::Serialize for CreateBookRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateBookResponseView<'a> { + /// Field 1: `book` + pub book: ::buffa::MessageFieldView< + super::super::__buffa::view::BookView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateBookResponseView<'a> { + type Owned = super::super::CreateBookResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.book.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.book = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateBookResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateBookResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateBookResponse { + book: match self.book.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Book, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateBookResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateBookResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.book.as_option() { + __map.serialize_entry("book", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateBookResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBookResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBookResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookResponse"; + } + ::buffa::impl_default_view_instance!(CreateBookResponseView); + ::buffa::impl_view_reborrow!(CreateBookResponseView); + /** Self-contained, `'static` owned view of a `CreateBookResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateBookResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateBookResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateBookResponseOwnedView( + ::buffa::OwnedView>, + ); + impl CreateBookResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateBookResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateBookResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateBookResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateBookResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book` + #[must_use] + pub fn book( + &self, + ) -> &::buffa::MessageFieldView> { + &self.0.reborrow().book + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for CreateBookResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + CreateBookResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateBookResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for CreateBookResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateBookResponse { + type View<'a> = CreateBookResponseView<'a>; + type ViewHandle = CreateBookResponseOwnedView; + } + impl ::serde::Serialize for CreateBookResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct UpdateBookRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + /// Field 2: `title` + pub title: ::core::option::Option<&'a str>, + /// Field 3: `author` + pub author: ::core::option::Option<&'a str>, + /// Field 4: `price_fcfa` + pub price_fcfa: ::core::option::Option, + /// Field 5: `condition` + pub condition: ::core::option::Option< + ::buffa::EnumValue, + >, + /// Field 6: `description` + pub description: ::core::option::Option<&'a str>, + /// Field 7: `category_id` + pub category_id: ::core::option::Option, + /// Field 8: `refundable` + pub refundable: ::core::option::Option, + /// Field 9: `swapable` + pub swapable: ::core::option::Option, + /// Field 10: `status` + pub status: ::core::option::Option< + ::buffa::EnumValue, + >, + /// Field 11: `picture_upload_ids` + pub picture_upload_ids: ::buffa::RepeatedView<'a, &'a str>, + /// Field 12: `picture_types` (map) + pub picture_types: ::buffa::MapView< + 'a, + &'a str, + ::buffa::EnumValue, + >, + /// Field 13: `location` + pub location: ::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for UpdateBookRequestView<'a> { + type Owned = super::super::UpdateBookRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.title = Some(::buffa::types::borrow_str(&mut cur)?); + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.author = Some(::buffa::types::borrow_str(&mut cur)?); + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.price_fcfa = Some(::buffa::types::decode_int64(&mut cur)?); + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.condition = Some( + ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ), + ); + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.description = Some(::buffa::types::borrow_str(&mut cur)?); + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.category_id = Some(::buffa::types::decode_int64(&mut cur)?); + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.refundable = Some(::buffa::types::decode_bool(&mut cur)?); + } + 9u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.swapable = Some(::buffa::types::decode_bool(&mut cur)?); + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.status = Some( + ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ), + ); + } + 13u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.location.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.location = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 11u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __elem = ::buffa::types::borrow_str(&mut cur)?; + ctx.register_element_memory( + ::buffa::__private::element_footprint(&__elem), + )?; + view.picture_upload_ids.push(__elem); + } + 12u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let entry_bytes = ::buffa::types::borrow_bytes(&mut cur)?; + let mut entry_cur: &'a [u8] = entry_bytes; + let mut key = ""; + let mut val = ::core::default::Default::default(); + ctx.register_element_memory( + ::buffa::__private::element_footprint(&key) + + ::buffa::__private::element_footprint(&val), + )?; + while !entry_cur.is_empty() { + let entry_tag = ::buffa::encoding::Tag::decode( + &mut entry_cur, + )?; + match entry_tag.field_number() { + 1 => { + ::buffa::encoding::check_wire_type( + entry_tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + key = ::buffa::types::borrow_str(&mut entry_cur)?; + } + 2 => { + ::buffa::encoding::check_wire_type( + entry_tag, + ::buffa::encoding::WireType::Varint, + )?; + val = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut entry_cur)?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth( + entry_tag, + &mut entry_cur, + ctx.depth(), + )?; + } + } + } + view.picture_types.push(key, val); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::UpdateBookRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::UpdateBookRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::UpdateBookRequest { + book_id: self.book_id.to_string(), + title: self.title.map(|s| s.to_string()), + author: self.author.map(|s| s.to_string()), + price_fcfa: self.price_fcfa, + condition: self.condition, + description: self.description.map(|s| s.to_string()), + category_id: self.category_id, + refundable: self.refundable, + swapable: self.swapable, + status: self.status, + picture_upload_ids: self + .picture_upload_ids + .iter() + .map(|s| s.to_string()) + .collect(), + picture_types: self + .picture_types + .iter() + .map(|(k, v)| (k.to_string(), *v)) + .collect(), + location: match self.location.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::LatLng, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for UpdateBookRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if let Some(ref v) = self.title { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(ref v) = self.author { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(v) = self.price_fcfa { + size += 1u64 + ::buffa::types::int64_encoded_len(v) as u64; + } + if let Some(ref v) = self.condition { + size += 1u64 + ::buffa::types::int32_encoded_len(v.to_i32()) as u64; + } + if let Some(ref v) = self.description { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + if let Some(v) = self.category_id { + size += 1u64 + ::buffa::types::int64_encoded_len(v) as u64; + } + if self.refundable.is_some() { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.swapable.is_some() { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if let Some(ref v) = self.status { + size += 1u64 + ::buffa::types::int32_encoded_len(v.to_i32()) as u64; + } + for v in &self.picture_upload_ids { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + #[allow(clippy::for_kv_map)] + for (k, v) in &self.picture_types { + let entry_size: u64 = 1u64 + + ::buffa::types::string_encoded_len(k) as u64 + 1u64 + + ::buffa::types::int32_encoded_len(v.to_i32()) as u64; + size + += 1u64 + ::buffa::encoding::varint_len(entry_size) as u64 + + entry_size; + } + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + if let Some(ref v) = self.title { + ::buffa::types::put_string_field(2u32, v, buf); + } + if let Some(ref v) = self.author { + ::buffa::types::put_string_field(3u32, v, buf); + } + if let Some(v) = self.price_fcfa { + ::buffa::types::put_int64_field(4u32, v, buf); + } + if let Some(ref v) = self.condition { + ::buffa::types::put_int32_field(5u32, v.to_i32(), buf); + } + if let Some(ref v) = self.description { + ::buffa::types::put_string_field(6u32, v, buf); + } + if let Some(v) = self.category_id { + ::buffa::types::put_int64_field(7u32, v, buf); + } + if let Some(v) = self.refundable { + ::buffa::types::put_bool_field(8u32, v, buf); + } + if let Some(v) = self.swapable { + ::buffa::types::put_bool_field(9u32, v, buf); + } + if let Some(ref v) = self.status { + ::buffa::types::put_int32_field(10u32, v.to_i32(), buf); + } + for v in &self.picture_upload_ids { + ::buffa::types::put_string_field(11u32, v, buf); + } + for (k, v) in &self.picture_types { + let entry_size: u64 = 1u64 + + ::buffa::types::string_encoded_len(k) as u64 + 1u64 + + ::buffa::types::int32_encoded_len(v.to_i32()) as u64; + ::buffa::encoding::Tag::new( + 12u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(entry_size, buf); + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::types::encode_string(k, buf); + ::buffa::encoding::Tag::new( + 2u32, + ::buffa::encoding::WireType::Varint, + ) + .encode(buf); + ::buffa::types::encode_int32(v.to_i32(), buf); + } + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 13u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for UpdateBookRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + if let ::core::option::Option::Some(__v) = self.title { + __map.serialize_entry("title", __v)?; + } + if let ::core::option::Option::Some(__v) = self.author { + __map.serialize_entry("author", __v)?; + } + if let ::core::option::Option::Some(__v) = self.price_fcfa { + __map + .serialize_entry( + "priceFcfa", + &::buffa::json_helpers::ProtoJson(&__v), + )?; + } + if let ::core::option::Option::Some(ref __v) = self.condition { + __map.serialize_entry("condition", __v)?; + } + if let ::core::option::Option::Some(__v) = self.description { + __map.serialize_entry("description", __v)?; + } + if let ::core::option::Option::Some(__v) = self.category_id { + __map + .serialize_entry( + "categoryId", + &::buffa::json_helpers::ProtoJson(&__v), + )?; + } + if let ::core::option::Option::Some(__v) = self.refundable { + __map.serialize_entry("refundable", &__v)?; + } + if let ::core::option::Option::Some(__v) = self.swapable { + __map.serialize_entry("swapable", &__v)?; + } + if let ::core::option::Option::Some(ref __v) = self.status { + __map.serialize_entry("status", __v)?; + } + if !self.picture_upload_ids.is_empty() { + __map + .serialize_entry("pictureUploadIds", &*self.picture_upload_ids)?; + } + if !self.picture_types.is_empty() { + struct _WM<'__a, '__x>( + &'__x ::buffa::MapView< + '__x, + &'__a str, + ::buffa::EnumValue, + >, + ); + impl<'__a> ::serde::Serialize for _WM<'__a, '_> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __m = __s + .serialize_map(::core::option::Option::Some(self.0.len()))?; + for (k, v) in self.0.iter_unique() { + __m.serialize_entry(k, v)?; + } + __m.end() + } + } + __map.serialize_entry("pictureTypes", &_WM(&self.picture_types))?; + } + { + if let ::core::option::Option::Some(__v) = self.location.as_option() + { + __map.serialize_entry("location", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for UpdateBookRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UpdateBookRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.UpdateBookRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateBookRequest"; + } + ::buffa::impl_default_view_instance!(UpdateBookRequestView); + ::buffa::impl_view_reborrow!(UpdateBookRequestView); + /** Self-contained, `'static` owned view of a `UpdateBookRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`UpdateBookRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`UpdateBookRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct UpdateBookRequestOwnedView( + ::buffa::OwnedView>, + ); + impl UpdateBookRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateBookRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateBookRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::UpdateBookRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateBookRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`UpdateBookRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &UpdateBookRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UpdateBookRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + /// Field 2: `title` + #[must_use] + pub fn title(&self) -> ::core::option::Option<&'_ str> { + self.0.reborrow().title + } + /// Field 3: `author` + #[must_use] + pub fn author(&self) -> ::core::option::Option<&'_ str> { + self.0.reborrow().author + } + /// Field 4: `price_fcfa` + #[must_use] + pub fn price_fcfa(&self) -> ::core::option::Option { + self.0.reborrow().price_fcfa + } + /// Field 5: `condition` + #[must_use] + pub fn condition( + &self, + ) -> ::core::option::Option< + ::buffa::EnumValue, + > { + self.0.reborrow().condition + } + /// Field 6: `description` + #[must_use] + pub fn description(&self) -> ::core::option::Option<&'_ str> { + self.0.reborrow().description + } + /// Field 7: `category_id` + #[must_use] + pub fn category_id(&self) -> ::core::option::Option { + self.0.reborrow().category_id + } + /// Field 8: `refundable` + #[must_use] + pub fn refundable(&self) -> ::core::option::Option { + self.0.reborrow().refundable + } + /// Field 9: `swapable` + #[must_use] + pub fn swapable(&self) -> ::core::option::Option { + self.0.reborrow().swapable + } + /// Field 10: `status` + #[must_use] + pub fn status( + &self, + ) -> ::core::option::Option<::buffa::EnumValue> { + self.0.reborrow().status + } + /// Field 11: `picture_upload_ids` + #[must_use] + pub fn picture_upload_ids(&self) -> &::buffa::RepeatedView<'_, &'_ str> { + &self.0.reborrow().picture_upload_ids + } + /// Field 12: `picture_types` (map) + #[must_use] + pub fn picture_types( + &self, + ) -> &::buffa::MapView< + '_, + &'_ str, + ::buffa::EnumValue, + > { + &self.0.reborrow().picture_types + } + /// Field 13: `location` + #[must_use] + pub fn location( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'_>, + > { + &self.0.reborrow().location + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for UpdateBookRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + UpdateBookRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: UpdateBookRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for UpdateBookRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::UpdateBookRequest { + type View<'a> = UpdateBookRequestView<'a>; + type ViewHandle = UpdateBookRequestOwnedView; + } + impl ::serde::Serialize for UpdateBookRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct UpdateBookResponseView<'a> { + /// Field 1: `book` + pub book: ::buffa::MessageFieldView< + super::super::__buffa::view::BookView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for UpdateBookResponseView<'a> { + type Owned = super::super::UpdateBookResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.book.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.book = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::UpdateBookResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::UpdateBookResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::UpdateBookResponse { + book: match self.book.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Book, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for UpdateBookResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for UpdateBookResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.book.as_option() { + __map.serialize_entry("book", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for UpdateBookResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UpdateBookResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.UpdateBookResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UpdateBookResponse"; + } + ::buffa::impl_default_view_instance!(UpdateBookResponseView); + ::buffa::impl_view_reborrow!(UpdateBookResponseView); + /** Self-contained, `'static` owned view of a `UpdateBookResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`UpdateBookResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`UpdateBookResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct UpdateBookResponseOwnedView( + ::buffa::OwnedView>, + ); + impl UpdateBookResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateBookResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateBookResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::UpdateBookResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UpdateBookResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`UpdateBookResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &UpdateBookResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UpdateBookResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book` + #[must_use] + pub fn book( + &self, + ) -> &::buffa::MessageFieldView> { + &self.0.reborrow().book + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for UpdateBookResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + UpdateBookResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: UpdateBookResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for UpdateBookResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::UpdateBookResponse { + type View<'a> = UpdateBookResponseView<'a>; + type ViewHandle = UpdateBookResponseOwnedView; + } + impl ::serde::Serialize for UpdateBookResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct DeleteBookRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for DeleteBookRequestView<'a> { + type Owned = super::super::DeleteBookRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::DeleteBookRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::DeleteBookRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::DeleteBookRequest { + book_id: self.book_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for DeleteBookRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for DeleteBookRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for DeleteBookRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DeleteBookRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.DeleteBookRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteBookRequest"; + } + ::buffa::impl_default_view_instance!(DeleteBookRequestView); + ::buffa::impl_view_reborrow!(DeleteBookRequestView); + /** Self-contained, `'static` owned view of a `DeleteBookRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`DeleteBookRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`DeleteBookRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct DeleteBookRequestOwnedView( + ::buffa::OwnedView>, + ); + impl DeleteBookRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteBookRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteBookRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::DeleteBookRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteBookRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`DeleteBookRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &DeleteBookRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::DeleteBookRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for DeleteBookRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + DeleteBookRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: DeleteBookRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for DeleteBookRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::DeleteBookRequest { + type View<'a> = DeleteBookRequestView<'a>; + type ViewHandle = DeleteBookRequestOwnedView; + } + impl ::serde::Serialize for DeleteBookRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct DeleteBookResponseView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for DeleteBookResponseView<'a> { + type Owned = super::super::DeleteBookResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::DeleteBookResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::DeleteBookResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::DeleteBookResponse { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for DeleteBookResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for DeleteBookResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for DeleteBookResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DeleteBookResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.DeleteBookResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteBookResponse"; + } + ::buffa::impl_default_view_instance!(DeleteBookResponseView); + ::buffa::impl_view_reborrow!(DeleteBookResponseView); + /** Self-contained, `'static` owned view of a `DeleteBookResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`DeleteBookResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`DeleteBookResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct DeleteBookResponseOwnedView( + ::buffa::OwnedView>, + ); + impl DeleteBookResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteBookResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteBookResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::DeleteBookResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteBookResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`DeleteBookResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &DeleteBookResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::DeleteBookResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for DeleteBookResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + DeleteBookResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: DeleteBookResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for DeleteBookResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::DeleteBookResponse { + type View<'a> = DeleteBookResponseView<'a>; + type ViewHandle = DeleteBookResponseOwnedView; + } + impl ::serde::Serialize for DeleteBookResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to the boosts table (payment_type = boost). + #[derive(Clone, Debug, Default)] + pub struct BoostView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `book_id` + pub book_id: &'a str, + /// Field 3: `amount_fcfa` + pub amount_fcfa: i64, + /// Field 4: `expires_at` + pub expires_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 5: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for BoostView<'a> { + type Owned = super::super::Boost; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.amount_fcfa = ::buffa::types::decode_int64(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.expires_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.expires_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Boost { + id: self.id.to_string(), + book_id: self.book_id.to_string(), + amount_fcfa: self.amount_fcfa, + expires_at: match self.expires_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for BoostView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if self.amount_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + if self.expires_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.expires_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.book_id, buf); + } + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(3u32, self.amount_fcfa, buf); + } + if self.expires_at.is_set() { + ::buffa::types::put_len_delimited_header( + 4u32, + u64::from(__cache.consume_next()), + buf, + ); + self.expires_at.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for BoostView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.amount_fcfa) { + __map + .serialize_entry( + "amountFcfa", + &::buffa::json_helpers::ProtoJson(&self.amount_fcfa), + )?; + } + { + if let ::core::option::Option::Some(__v) = self + .expires_at + .as_option() + { + __map.serialize_entry("expiresAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for BoostView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Boost"; + const FULL_NAME: &'static str = "bookbridge.v1.Boost"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Boost"; + } + ::buffa::impl_default_view_instance!(BoostView); + ::buffa::impl_view_reborrow!(BoostView); + /** Self-contained, `'static` owned view of a `Boost` message. + + Wraps [`::buffa::OwnedView`]`<`[`BoostView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`BoostView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct BoostOwnedView(::buffa::OwnedView>); + impl BoostOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BoostOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BoostOwnedView(::buffa::OwnedView::decode_with_options(bytes, opts)?), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Boost, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BoostOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`BoostView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &BoostView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Boost { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + /// Field 3: `amount_fcfa` + #[must_use] + pub fn amount_fcfa(&self) -> i64 { + self.0.reborrow().amount_fcfa + } + /// Field 4: `expires_at` + #[must_use] + pub fn expires_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().expires_at + } + /// Field 5: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for BoostOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + BoostOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: BoostOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for BoostOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Boost { + type View<'a> = BoostView<'a>; + type ViewHandle = BoostOwnedView; + } + impl ::serde::Serialize for BoostOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateBoostRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + /// Field 2: `amount_fcfa` + pub amount_fcfa: i64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateBoostRequestView<'a> { + type Owned = super::super::CreateBoostRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.amount_fcfa = ::buffa::types::decode_int64(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateBoostRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateBoostRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateBoostRequest { + book_id: self.book_id.to_string(), + amount_fcfa: self.amount_fcfa, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateBoostRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if self.amount_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(2u32, self.amount_fcfa, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateBoostRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.amount_fcfa) { + __map + .serialize_entry( + "amountFcfa", + &::buffa::json_helpers::ProtoJson(&self.amount_fcfa), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateBoostRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBoostRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBoostRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBoostRequest"; + } + ::buffa::impl_default_view_instance!(CreateBoostRequestView); + ::buffa::impl_view_reborrow!(CreateBoostRequestView); + /** Self-contained, `'static` owned view of a `CreateBoostRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateBoostRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateBoostRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateBoostRequestOwnedView( + ::buffa::OwnedView>, + ); + impl CreateBoostRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBoostRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBoostRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateBoostRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBoostRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateBoostRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateBoostRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateBoostRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + /// Field 2: `amount_fcfa` + #[must_use] + pub fn amount_fcfa(&self) -> i64 { + self.0.reborrow().amount_fcfa + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for CreateBoostRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + CreateBoostRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateBoostRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for CreateBoostRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateBoostRequest { + type View<'a> = CreateBoostRequestView<'a>; + type ViewHandle = CreateBoostRequestOwnedView; + } + impl ::serde::Serialize for CreateBoostRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateBoostResponseView<'a> { + /// Field 1: `boost` + pub boost: ::buffa::MessageFieldView< + super::super::__buffa::view::BoostView<'a>, + >, + /// Field 2: `fapshi_transaction_id` + pub fapshi_transaction_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateBoostResponseView<'a> { + type Owned = super::super::CreateBoostResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.boost.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.boost = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.fapshi_transaction_id = ::buffa::types::borrow_str( + &mut cur, + )?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateBoostResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateBoostResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateBoostResponse { + boost: match self.boost.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Boost, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + fapshi_transaction_id: self.fapshi_transaction_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateBoostResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.boost.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.boost.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.fapshi_transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len( + &self.fapshi_transaction_id, + ) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.boost.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.boost.write_to(__cache, buf); + } + if !self.fapshi_transaction_id.is_empty() { + ::buffa::types::put_string_field( + 2u32, + &self.fapshi_transaction_id, + buf, + ); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateBoostResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.boost.as_option() { + __map.serialize_entry("boost", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str( + self.fapshi_transaction_id, + ) { + __map + .serialize_entry( + "fapshiTransactionId", + self.fapshi_transaction_id, + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateBoostResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBoostResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBoostResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBoostResponse"; + } + ::buffa::impl_default_view_instance!(CreateBoostResponseView); + ::buffa::impl_view_reborrow!(CreateBoostResponseView); + /** Self-contained, `'static` owned view of a `CreateBoostResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateBoostResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateBoostResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateBoostResponseOwnedView( + ::buffa::OwnedView>, + ); + impl CreateBoostResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBoostResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBoostResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateBoostResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBoostResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateBoostResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateBoostResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateBoostResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `boost` + #[must_use] + pub fn boost( + &self, + ) -> &::buffa::MessageFieldView> { + &self.0.reborrow().boost + } + /// Field 2: `fapshi_transaction_id` + #[must_use] + pub fn fapshi_transaction_id(&self) -> &'_ str { + self.0.reborrow().fapshi_transaction_id + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for CreateBoostResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateBoostResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateBoostResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for CreateBoostResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateBoostResponse { + type View<'a> = CreateBoostResponseView<'a>; + type ViewHandle = CreateBoostResponseOwnedView; + } + impl ::serde::Serialize for CreateBoostResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetBoostStatusRequestView<'a> { + /// Field 1: `boost_id` + pub boost_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetBoostStatusRequestView<'a> { + type Owned = super::super::GetBoostStatusRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.boost_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetBoostStatusRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetBoostStatusRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetBoostStatusRequest { + boost_id: self.boost_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetBoostStatusRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.boost_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.boost_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.boost_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.boost_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetBoostStatusRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.boost_id) { + __map.serialize_entry("boostId", self.boost_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetBoostStatusRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetBoostStatusRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetBoostStatusRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBoostStatusRequest"; + } + ::buffa::impl_default_view_instance!(GetBoostStatusRequestView); + ::buffa::impl_view_reborrow!(GetBoostStatusRequestView); + /** Self-contained, `'static` owned view of a `GetBoostStatusRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetBoostStatusRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetBoostStatusRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetBoostStatusRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetBoostStatusRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBoostStatusRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBoostStatusRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetBoostStatusRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBoostStatusRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetBoostStatusRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetBoostStatusRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetBoostStatusRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `boost_id` + #[must_use] + pub fn boost_id(&self) -> &'_ str { + self.0.reborrow().boost_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetBoostStatusRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetBoostStatusRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetBoostStatusRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetBoostStatusRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetBoostStatusRequest { + type View<'a> = GetBoostStatusRequestView<'a>; + type ViewHandle = GetBoostStatusRequestOwnedView; + } + impl ::serde::Serialize for GetBoostStatusRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetBoostStatusResponseView<'a> { + /// Field 1: `boost` + pub boost: ::buffa::MessageFieldView< + super::super::__buffa::view::BoostView<'a>, + >, + /// Field 2: `outcome` + pub outcome: ::buffa::MessageFieldView< + super::super::__buffa::view::PaymentOutcomeView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetBoostStatusResponseView<'a> { + type Owned = super::super::GetBoostStatusResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.boost.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.boost = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.outcome.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.outcome = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetBoostStatusResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetBoostStatusResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetBoostStatusResponse { + boost: match self.boost.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Boost, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + outcome: match self.outcome.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::PaymentOutcome, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetBoostStatusResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.boost.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.boost.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.outcome.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.outcome.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.boost.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.boost.write_to(__cache, buf); + } + if self.outcome.is_set() { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + self.outcome.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetBoostStatusResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.boost.as_option() { + __map.serialize_entry("boost", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self.outcome.as_option() { + __map.serialize_entry("outcome", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetBoostStatusResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetBoostStatusResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetBoostStatusResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetBoostStatusResponse"; + } + ::buffa::impl_default_view_instance!(GetBoostStatusResponseView); + ::buffa::impl_view_reborrow!(GetBoostStatusResponseView); + /** Self-contained, `'static` owned view of a `GetBoostStatusResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetBoostStatusResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetBoostStatusResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetBoostStatusResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetBoostStatusResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBoostStatusResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBoostStatusResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetBoostStatusResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetBoostStatusResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetBoostStatusResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetBoostStatusResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetBoostStatusResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `boost` + #[must_use] + pub fn boost( + &self, + ) -> &::buffa::MessageFieldView> { + &self.0.reborrow().boost + } + /// Field 2: `outcome` + #[must_use] + pub fn outcome( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::PaymentOutcomeView<'_>, + > { + &self.0.reborrow().outcome + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetBoostStatusResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetBoostStatusResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetBoostStatusResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetBoostStatusResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetBoostStatusResponse { + type View<'a> = GetBoostStatusResponseView<'a>; + type ViewHandle = GetBoostStatusResponseOwnedView; + } + impl ::serde::Serialize for GetBoostStatusResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct PaymentOutcomeView<'a> { + /// Field 1: `status` + pub status: &'a str, + /// Field 2: `message` + pub message: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for PaymentOutcomeView<'a> { + type Owned = super::super::PaymentOutcome; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.status = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.message = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::PaymentOutcome, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::PaymentOutcome, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::PaymentOutcome { + status: self.status.to_string(), + message: self.message.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for PaymentOutcomeView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.status.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.status) as u64; + } + if !self.message.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.message) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.status.is_empty() { + ::buffa::types::put_string_field(1u32, &self.status, buf); + } + if !self.message.is_empty() { + ::buffa::types::put_string_field(2u32, &self.message, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for PaymentOutcomeView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.status) { + __map.serialize_entry("status", self.status)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.message) { + __map.serialize_entry("message", self.message)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for PaymentOutcomeView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "PaymentOutcome"; + const FULL_NAME: &'static str = "bookbridge.v1.PaymentOutcome"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.PaymentOutcome"; + } + ::buffa::impl_default_view_instance!(PaymentOutcomeView); + ::buffa::impl_view_reborrow!(PaymentOutcomeView); + /** Self-contained, `'static` owned view of a `PaymentOutcome` message. + + Wraps [`::buffa::OwnedView`]`<`[`PaymentOutcomeView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`PaymentOutcomeView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct PaymentOutcomeOwnedView( + ::buffa::OwnedView>, + ); + impl PaymentOutcomeOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PaymentOutcomeOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PaymentOutcomeOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::PaymentOutcome, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PaymentOutcomeOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`PaymentOutcomeView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &PaymentOutcomeView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::PaymentOutcome { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `status` + #[must_use] + pub fn status(&self) -> &'_ str { + self.0.reborrow().status + } + /// Field 2: `message` + #[must_use] + pub fn message(&self) -> &'_ str { + self.0.reborrow().message + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for PaymentOutcomeOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + PaymentOutcomeOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: PaymentOutcomeOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for PaymentOutcomeOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::PaymentOutcome { + type View<'a> = PaymentOutcomeView<'a>; + type ViewHandle = PaymentOutcomeOwnedView; + } + impl ::serde::Serialize for PaymentOutcomeOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateDonationRequestView<'a> { + /// Field 1: `amount_fcfa` + pub amount_fcfa: i64, + /// Field 2: `message` + pub message: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateDonationRequestView<'a> { + type Owned = super::super::CreateDonationRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.amount_fcfa = ::buffa::types::decode_int64(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.message = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateDonationRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateDonationRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateDonationRequest { + amount_fcfa: self.amount_fcfa, + message: self.message.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateDonationRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.amount_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + if !self.message.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.message) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(1u32, self.amount_fcfa, buf); + } + if !self.message.is_empty() { + ::buffa::types::put_string_field(2u32, &self.message, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateDonationRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.amount_fcfa) { + __map + .serialize_entry( + "amountFcfa", + &::buffa::json_helpers::ProtoJson(&self.amount_fcfa), + )?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.message) { + __map.serialize_entry("message", self.message)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateDonationRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateDonationRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateDonationRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateDonationRequest"; + } + ::buffa::impl_default_view_instance!(CreateDonationRequestView); + ::buffa::impl_view_reborrow!(CreateDonationRequestView); + /** Self-contained, `'static` owned view of a `CreateDonationRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateDonationRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateDonationRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateDonationRequestOwnedView( + ::buffa::OwnedView>, + ); + impl CreateDonationRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateDonationRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateDonationRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateDonationRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateDonationRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateDonationRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateDonationRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateDonationRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `amount_fcfa` + #[must_use] + pub fn amount_fcfa(&self) -> i64 { + self.0.reborrow().amount_fcfa + } + /// Field 2: `message` + #[must_use] + pub fn message(&self) -> &'_ str { + self.0.reborrow().message + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for CreateDonationRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateDonationRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateDonationRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for CreateDonationRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateDonationRequest { + type View<'a> = CreateDonationRequestView<'a>; + type ViewHandle = CreateDonationRequestOwnedView; + } + impl ::serde::Serialize for CreateDonationRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct DonationView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `amount_fcfa` + pub amount_fcfa: i64, + /// Field 3: `message` + pub message: &'a str, + /// Field 4: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for DonationView<'a> { + type Owned = super::super::Donation; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.amount_fcfa = ::buffa::types::decode_int64(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.message = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Donation { + id: self.id.to_string(), + amount_fcfa: self.amount_fcfa, + message: self.message.to_string(), + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for DonationView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if self.amount_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + if !self.message.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.message) as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(2u32, self.amount_fcfa, buf); + } + if !self.message.is_empty() { + ::buffa::types::put_string_field(3u32, &self.message, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 4u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for DonationView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.amount_fcfa) { + __map + .serialize_entry( + "amountFcfa", + &::buffa::json_helpers::ProtoJson(&self.amount_fcfa), + )?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.message) { + __map.serialize_entry("message", self.message)?; + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for DonationView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Donation"; + const FULL_NAME: &'static str = "bookbridge.v1.Donation"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Donation"; + } + ::buffa::impl_default_view_instance!(DonationView); + ::buffa::impl_view_reborrow!(DonationView); + /** Self-contained, `'static` owned view of a `Donation` message. + + Wraps [`::buffa::OwnedView`]`<`[`DonationView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`DonationView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct DonationOwnedView(::buffa::OwnedView>); + impl DonationOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DonationOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DonationOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Donation, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DonationOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`DonationView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &DonationView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Donation { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `amount_fcfa` + #[must_use] + pub fn amount_fcfa(&self) -> i64 { + self.0.reborrow().amount_fcfa + } + /// Field 3: `message` + #[must_use] + pub fn message(&self) -> &'_ str { + self.0.reborrow().message + } + /// Field 4: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for DonationOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + DonationOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: DonationOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for DonationOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Donation { + type View<'a> = DonationView<'a>; + type ViewHandle = DonationOwnedView; + } + impl ::serde::Serialize for DonationOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateDonationResponseView<'a> { + /// Field 1: `donation` + pub donation: ::buffa::MessageFieldView< + super::super::__buffa::view::DonationView<'a>, + >, + /// Field 2: `fapshi_transaction_id` + pub fapshi_transaction_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateDonationResponseView<'a> { + type Owned = super::super::CreateDonationResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.donation.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.donation = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.fapshi_transaction_id = ::buffa::types::borrow_str( + &mut cur, + )?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateDonationResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateDonationResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateDonationResponse { + donation: match self.donation.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Donation, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + fapshi_transaction_id: self.fapshi_transaction_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateDonationResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.donation.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.donation.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.fapshi_transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len( + &self.fapshi_transaction_id, + ) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.donation.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.donation.write_to(__cache, buf); + } + if !self.fapshi_transaction_id.is_empty() { + ::buffa::types::put_string_field( + 2u32, + &self.fapshi_transaction_id, + buf, + ); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateDonationResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.donation.as_option() + { + __map.serialize_entry("donation", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str( + self.fapshi_transaction_id, + ) { + __map + .serialize_entry( + "fapshiTransactionId", + self.fapshi_transaction_id, + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateDonationResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateDonationResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateDonationResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateDonationResponse"; + } + ::buffa::impl_default_view_instance!(CreateDonationResponseView); + ::buffa::impl_view_reborrow!(CreateDonationResponseView); + /** Self-contained, `'static` owned view of a `CreateDonationResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateDonationResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateDonationResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateDonationResponseOwnedView( + ::buffa::OwnedView>, + ); + impl CreateDonationResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateDonationResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateDonationResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateDonationResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateDonationResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateDonationResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateDonationResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateDonationResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `donation` + #[must_use] + pub fn donation( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::DonationView<'_>, + > { + &self.0.reborrow().donation + } + /// Field 2: `fapshi_transaction_id` + #[must_use] + pub fn fapshi_transaction_id(&self) -> &'_ str { + self.0.reborrow().fapshi_transaction_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for CreateDonationResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateDonationResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateDonationResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for CreateDonationResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateDonationResponse { + type View<'a> = CreateDonationResponseView<'a>; + type ViewHandle = CreateDonationResponseOwnedView; + } + impl ::serde::Serialize for CreateDonationResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to conversation_messages. + #[derive(Clone, Debug, Default)] + pub struct MessageView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `conversation_id` + pub conversation_id: &'a str, + /// Field 3: `user_id` + pub user_id: &'a str, + /// Field 4: `content` + pub content: &'a str, + /// Field 5: `attachment` + pub attachment: ::buffa::MessageFieldView< + super::super::__buffa::view::UploadAttachmentView<'a>, + >, + /// Field 6: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for MessageView<'a> { + type Owned = super::super::Message; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.conversation_id = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.user_id = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.content = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.attachment.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.attachment = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Message { + id: self.id.to_string(), + conversation_id: self.conversation_id.to_string(), + user_id: self.user_id.to_string(), + content: self.content.to_string(), + attachment: match self.attachment.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::UploadAttachment, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for MessageView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.conversation_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.conversation_id) + as u64; + } + if !self.user_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.user_id) as u64; + } + if !self.content.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.content) as u64; + } + if self.attachment.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.attachment.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.conversation_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.conversation_id, buf); + } + if !self.user_id.is_empty() { + ::buffa::types::put_string_field(3u32, &self.user_id, buf); + } + if !self.content.is_empty() { + ::buffa::types::put_string_field(4u32, &self.content, buf); + } + if self.attachment.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.attachment.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for MessageView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.conversation_id) { + __map.serialize_entry("conversationId", self.conversation_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.user_id) { + __map.serialize_entry("userId", self.user_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.content) { + __map.serialize_entry("content", self.content)?; + } + { + if let ::core::option::Option::Some(__v) = self + .attachment + .as_option() + { + __map.serialize_entry("attachment", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for MessageView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Message"; + const FULL_NAME: &'static str = "bookbridge.v1.Message"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Message"; + } + ::buffa::impl_default_view_instance!(MessageView); + ::buffa::impl_view_reborrow!(MessageView); + /** Self-contained, `'static` owned view of a `Message` message. + + Wraps [`::buffa::OwnedView`]`<`[`MessageView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`MessageView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct MessageOwnedView(::buffa::OwnedView>); + impl MessageOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MessageOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MessageOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Message, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MessageOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`MessageView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &MessageView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Message { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `conversation_id` + #[must_use] + pub fn conversation_id(&self) -> &'_ str { + self.0.reborrow().conversation_id + } + /// Field 3: `user_id` + #[must_use] + pub fn user_id(&self) -> &'_ str { + self.0.reborrow().user_id + } + /// Field 4: `content` + #[must_use] + pub fn content(&self) -> &'_ str { + self.0.reborrow().content + } + /// Field 5: `attachment` + #[must_use] + pub fn attachment( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::UploadAttachmentView<'_>, + > { + &self.0.reborrow().attachment + } + /// Field 6: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for MessageOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + MessageOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: MessageOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for MessageOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Message { + type View<'a> = MessageView<'a>; + type ViewHandle = MessageOwnedView; + } + impl ::serde::Serialize for MessageOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct UploadAttachmentView<'a> { + /// Field 1: `upload_id` + pub upload_id: &'a str, + /// Field 2: `url` + pub url: &'a str, + /// Field 3: `content_type` + pub content_type: &'a str, + /// Field 4: `file_name` + pub file_name: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for UploadAttachmentView<'a> { + type Owned = super::super::UploadAttachment; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.upload_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.url = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.content_type = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.file_name = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::UploadAttachment, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::UploadAttachment, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::UploadAttachment { + upload_id: self.upload_id.to_string(), + url: self.url.to_string(), + content_type: self.content_type.to_string(), + file_name: self.file_name.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for UploadAttachmentView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + if !self.url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.url) as u64; + } + if !self.content_type.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.content_type) + as u64; + } + if !self.file_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.file_name) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + if !self.url.is_empty() { + ::buffa::types::put_string_field(2u32, &self.url, buf); + } + if !self.content_type.is_empty() { + ::buffa::types::put_string_field(3u32, &self.content_type, buf); + } + if !self.file_name.is_empty() { + ::buffa::types::put_string_field(4u32, &self.file_name, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for UploadAttachmentView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.upload_id) { + __map.serialize_entry("uploadId", self.upload_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.url) { + __map.serialize_entry("url", self.url)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.content_type) { + __map.serialize_entry("contentType", self.content_type)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.file_name) { + __map.serialize_entry("fileName", self.file_name)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for UploadAttachmentView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "UploadAttachment"; + const FULL_NAME: &'static str = "bookbridge.v1.UploadAttachment"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.UploadAttachment"; + } + ::buffa::impl_default_view_instance!(UploadAttachmentView); + ::buffa::impl_view_reborrow!(UploadAttachmentView); + /** Self-contained, `'static` owned view of a `UploadAttachment` message. + + Wraps [`::buffa::OwnedView`]`<`[`UploadAttachmentView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`UploadAttachmentView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct UploadAttachmentOwnedView( + ::buffa::OwnedView>, + ); + impl UploadAttachmentOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UploadAttachmentOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UploadAttachmentOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::UploadAttachment, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UploadAttachmentOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`UploadAttachmentView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &UploadAttachmentView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UploadAttachment { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `upload_id` + #[must_use] + pub fn upload_id(&self) -> &'_ str { + self.0.reborrow().upload_id + } + /// Field 2: `url` + #[must_use] + pub fn url(&self) -> &'_ str { + self.0.reborrow().url + } + /// Field 3: `content_type` + #[must_use] + pub fn content_type(&self) -> &'_ str { + self.0.reborrow().content_type + } + /// Field 4: `file_name` + #[must_use] + pub fn file_name(&self) -> &'_ str { + self.0.reborrow().file_name + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for UploadAttachmentOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + UploadAttachmentOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: UploadAttachmentOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for UploadAttachmentOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::UploadAttachment { + type View<'a> = UploadAttachmentView<'a>; + type ViewHandle = UploadAttachmentOwnedView; + } + impl ::serde::Serialize for UploadAttachmentOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Conversation summary (conversations table + last message + unread count). + #[derive(Clone, Debug, Default)] + pub struct ConversationView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `book_id` + pub book_id: &'a str, + /// Field 3: `book` + pub book: ::buffa::MessageFieldView< + super::super::__buffa::view::BookSummaryView<'a>, + >, + /// Field 4: `other_participant` + pub other_participant: ::buffa::MessageFieldView< + super::super::__buffa::view::UserSummaryView<'a>, + >, + /// Field 5: `last_message` + pub last_message: &'a str, + /// Field 6: `last_message_at` + pub last_message_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 7: `unread_count` + pub unread_count: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ConversationView<'a> { + type Owned = super::super::Conversation; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.book.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.book = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.other_participant.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.other_participant = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.last_message = ::buffa::types::borrow_str(&mut cur)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.last_message_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.last_message_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.unread_count = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::Conversation, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::Conversation, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Conversation { + id: self.id.to_string(), + book_id: self.book_id.to_string(), + book: match self.book.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::BookSummary, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + other_participant: match self.other_participant.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::UserSummary, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + last_message: self.last_message.to_string(), + last_message_at: match self.last_message_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + unread_count: self.unread_count, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ConversationView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.other_participant.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.other_participant.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.last_message.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.last_message) + as u64; + } + if self.last_message_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.last_message_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.unread_count != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.unread_count) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.book_id, buf); + } + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 3u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + if self.other_participant.is_set() { + ::buffa::types::put_len_delimited_header( + 4u32, + u64::from(__cache.consume_next()), + buf, + ); + self.other_participant.write_to(__cache, buf); + } + if !self.last_message.is_empty() { + ::buffa::types::put_string_field(5u32, &self.last_message, buf); + } + if self.last_message_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.last_message_at.write_to(__cache, buf); + } + if self.unread_count != 0i32 { + ::buffa::types::put_int32_field(7u32, self.unread_count, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ConversationView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + { + if let ::core::option::Option::Some(__v) = self.book.as_option() { + __map.serialize_entry("book", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .other_participant + .as_option() + { + __map.serialize_entry("otherParticipant", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.last_message) { + __map.serialize_entry("lastMessage", self.last_message)?; + } + { + if let ::core::option::Option::Some(__v) = self + .last_message_at + .as_option() + { + __map.serialize_entry("lastMessageAt", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.unread_count) { + __map + .serialize_entry( + "unreadCount", + &::buffa::json_helpers::ProtoJson(&self.unread_count), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ConversationView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Conversation"; + const FULL_NAME: &'static str = "bookbridge.v1.Conversation"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Conversation"; + } + ::buffa::impl_default_view_instance!(ConversationView); + ::buffa::impl_view_reborrow!(ConversationView); + /** Self-contained, `'static` owned view of a `Conversation` message. + + Wraps [`::buffa::OwnedView`]`<`[`ConversationView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ConversationView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ConversationOwnedView(::buffa::OwnedView>); + impl ConversationOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConversationOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConversationOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Conversation, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConversationOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ConversationView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ConversationView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Conversation { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + /// Field 3: `book` + #[must_use] + pub fn book( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::BookSummaryView<'_>, + > { + &self.0.reborrow().book + } + /// Field 4: `other_participant` + #[must_use] + pub fn other_participant( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::UserSummaryView<'_>, + > { + &self.0.reborrow().other_participant + } + /// Field 5: `last_message` + #[must_use] + pub fn last_message(&self) -> &'_ str { + self.0.reborrow().last_message + } + /// Field 6: `last_message_at` + #[must_use] + pub fn last_message_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().last_message_at + } + /// Field 7: `unread_count` + #[must_use] + pub fn unread_count(&self) -> i32 { + self.0.reborrow().unread_count + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ConversationOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + ConversationOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ConversationOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ConversationOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Conversation { + type View<'a> = ConversationView<'a>; + type ViewHandle = ConversationOwnedView; + } + impl ::serde::Serialize for ConversationOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Lightweight book info for conversation list rows. + #[derive(Clone, Debug, Default)] + pub struct BookSummaryView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `title` + pub title: &'a str, + /// Field 3: `cover_url` + pub cover_url: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for BookSummaryView<'a> { + type Owned = super::super::BookSummary; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.title = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.cover_url = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::BookSummary, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::BookSummary, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::BookSummary { + id: self.id.to_string(), + title: self.title.to_string(), + cover_url: self.cover_url.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for BookSummaryView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.title.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.cover_url.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.cover_url) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.title.is_empty() { + ::buffa::types::put_string_field(2u32, &self.title, buf); + } + if !self.cover_url.is_empty() { + ::buffa::types::put_string_field(3u32, &self.cover_url, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for BookSummaryView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.title) { + __map.serialize_entry("title", self.title)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.cover_url) { + __map.serialize_entry("coverUrl", self.cover_url)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for BookSummaryView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "BookSummary"; + const FULL_NAME: &'static str = "bookbridge.v1.BookSummary"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookSummary"; + } + ::buffa::impl_default_view_instance!(BookSummaryView); + ::buffa::impl_view_reborrow!(BookSummaryView); + /** Self-contained, `'static` owned view of a `BookSummary` message. + + Wraps [`::buffa::OwnedView`]`<`[`BookSummaryView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`BookSummaryView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct BookSummaryOwnedView(::buffa::OwnedView>); + impl BookSummaryOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookSummaryOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookSummaryOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::BookSummary, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookSummaryOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`BookSummaryView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &BookSummaryView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::BookSummary { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `title` + #[must_use] + pub fn title(&self) -> &'_ str { + self.0.reborrow().title + } + /// Field 3: `cover_url` + #[must_use] + pub fn cover_url(&self) -> &'_ str { + self.0.reborrow().cover_url + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for BookSummaryOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + BookSummaryOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: BookSummaryOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for BookSummaryOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::BookSummary { + type View<'a> = BookSummaryView<'a>; + type ViewHandle = BookSummaryOwnedView; + } + impl ::serde::Serialize for BookSummaryOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListConversationsRequestView<'a> { + /// Field 1: `page_token` + pub page_token: &'a str, + /// Field 2: `page_size` + pub page_size: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListConversationsRequestView<'a> { + type Owned = super::super::ListConversationsRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListConversationsRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListConversationsRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListConversationsRequest { + page_token: self.page_token.to_string(), + page_size: self.page_size, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListConversationsRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListConversationsRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListConversationsRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListConversationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListConversationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListConversationsRequest"; + } + ::buffa::impl_default_view_instance!(ListConversationsRequestView); + ::buffa::impl_view_reborrow!(ListConversationsRequestView); + /** Self-contained, `'static` owned view of a `ListConversationsRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListConversationsRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListConversationsRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListConversationsRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListConversationsRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListConversationsRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListConversationsRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListConversationsRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListConversationsRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListConversationsRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListConversationsRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListConversationsRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 2: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListConversationsRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListConversationsRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListConversationsRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListConversationsRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListConversationsRequest { + type View<'a> = ListConversationsRequestView<'a>; + type ViewHandle = ListConversationsRequestOwnedView; + } + impl ::serde::Serialize for ListConversationsRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListConversationsResponseView<'a> { + /// Field 1: `conversations` + pub conversations: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::ConversationView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListConversationsResponseView<'a> { + type Owned = super::super::ListConversationsResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::ConversationView, + >(), + )?; + view.conversations + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListConversationsResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListConversationsResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListConversationsResponse { + conversations: self + .conversations + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListConversationsResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.conversations { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.conversations { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListConversationsResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.conversations.is_empty() { + __map.serialize_entry("conversations", &*self.conversations)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListConversationsResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListConversationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListConversationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListConversationsResponse"; + } + ::buffa::impl_default_view_instance!(ListConversationsResponseView); + ::buffa::impl_view_reborrow!(ListConversationsResponseView); + /** Self-contained, `'static` owned view of a `ListConversationsResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListConversationsResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListConversationsResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListConversationsResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListConversationsResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListConversationsResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListConversationsResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListConversationsResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListConversationsResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListConversationsResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListConversationsResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListConversationsResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `conversations` + #[must_use] + pub fn conversations( + &self, + ) -> &::buffa::RepeatedView< + '_, + super::super::__buffa::view::ConversationView<'_>, + > { + &self.0.reborrow().conversations + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListConversationsResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListConversationsResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListConversationsResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListConversationsResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListConversationsResponse { + type View<'a> = ListConversationsResponseView<'a>; + type ViewHandle = ListConversationsResponseOwnedView; + } + impl ::serde::Serialize for ListConversationsResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetOrCreateConversationRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetOrCreateConversationRequestView<'a> { + type Owned = super::super::GetOrCreateConversationRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetOrCreateConversationRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetOrCreateConversationRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetOrCreateConversationRequest { + book_id: self.book_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetOrCreateConversationRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetOrCreateConversationRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetOrCreateConversationRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetOrCreateConversationRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetOrCreateConversationRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetOrCreateConversationRequest"; + } + ::buffa::impl_default_view_instance!(GetOrCreateConversationRequestView); + ::buffa::impl_view_reborrow!(GetOrCreateConversationRequestView); + /** Self-contained, `'static` owned view of a `GetOrCreateConversationRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetOrCreateConversationRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetOrCreateConversationRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetOrCreateConversationRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetOrCreateConversationRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetOrCreateConversationRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetOrCreateConversationRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetOrCreateConversationRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetOrCreateConversationRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`GetOrCreateConversationRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetOrCreateConversationRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::GetOrCreateConversationRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetOrCreateConversationRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetOrCreateConversationRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetOrCreateConversationRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetOrCreateConversationRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetOrCreateConversationRequest { + type View<'a> = GetOrCreateConversationRequestView<'a>; + type ViewHandle = GetOrCreateConversationRequestOwnedView; + } + impl ::serde::Serialize for GetOrCreateConversationRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetOrCreateConversationResponseView<'a> { + /// Field 1: `conversation` + pub conversation: ::buffa::MessageFieldView< + super::super::__buffa::view::ConversationView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetOrCreateConversationResponseView<'a> { + type Owned = super::super::GetOrCreateConversationResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.conversation.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.conversation = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetOrCreateConversationResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetOrCreateConversationResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetOrCreateConversationResponse { + conversation: match self.conversation.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Conversation, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetOrCreateConversationResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.conversation.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.conversation.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.conversation.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.conversation.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetOrCreateConversationResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self + .conversation + .as_option() + { + __map.serialize_entry("conversation", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetOrCreateConversationResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetOrCreateConversationResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetOrCreateConversationResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetOrCreateConversationResponse"; + } + ::buffa::impl_default_view_instance!(GetOrCreateConversationResponseView); + ::buffa::impl_view_reborrow!(GetOrCreateConversationResponseView); + /** Self-contained, `'static` owned view of a `GetOrCreateConversationResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetOrCreateConversationResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetOrCreateConversationResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetOrCreateConversationResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetOrCreateConversationResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetOrCreateConversationResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetOrCreateConversationResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetOrCreateConversationResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetOrCreateConversationResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`GetOrCreateConversationResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetOrCreateConversationResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::GetOrCreateConversationResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `conversation` + #[must_use] + pub fn conversation( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::ConversationView<'_>, + > { + &self.0.reborrow().conversation + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetOrCreateConversationResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetOrCreateConversationResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetOrCreateConversationResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetOrCreateConversationResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetOrCreateConversationResponse { + type View<'a> = GetOrCreateConversationResponseView<'a>; + type ViewHandle = GetOrCreateConversationResponseOwnedView; + } + impl ::serde::Serialize for GetOrCreateConversationResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMessagesRequestView<'a> { + /// Field 1: `conversation_id` + pub conversation_id: &'a str, + /// Field 2: `page_token` + pub page_token: &'a str, + /// Field 3: `page_size` + pub page_size: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMessagesRequestView<'a> { + type Owned = super::super::ListMessagesRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.conversation_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMessagesRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMessagesRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMessagesRequest { + conversation_id: self.conversation_id.to_string(), + page_token: self.page_token.to_string(), + page_size: self.page_size, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMessagesRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.conversation_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.conversation_id) + as u64; + } + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.conversation_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.conversation_id, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(3u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMessagesRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.conversation_id) { + __map.serialize_entry("conversationId", self.conversation_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMessagesRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMessagesRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMessagesRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMessagesRequest"; + } + ::buffa::impl_default_view_instance!(ListMessagesRequestView); + ::buffa::impl_view_reborrow!(ListMessagesRequestView); + /** Self-contained, `'static` owned view of a `ListMessagesRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMessagesRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMessagesRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMessagesRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListMessagesRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMessagesRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMessagesRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMessagesRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMessagesRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListMessagesRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMessagesRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMessagesRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `conversation_id` + #[must_use] + pub fn conversation_id(&self) -> &'_ str { + self.0.reborrow().conversation_id + } + /// Field 2: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 3: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListMessagesRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListMessagesRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMessagesRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ListMessagesRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMessagesRequest { + type View<'a> = ListMessagesRequestView<'a>; + type ViewHandle = ListMessagesRequestOwnedView; + } + impl ::serde::Serialize for ListMessagesRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMessagesResponseView<'a> { + /// Field 1: `messages` + pub messages: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::MessageView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMessagesResponseView<'a> { + type Owned = super::super::ListMessagesResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::MessageView, + >(), + )?; + view.messages + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMessagesResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMessagesResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMessagesResponse { + messages: self + .messages + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMessagesResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.messages { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.messages { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMessagesResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.messages.is_empty() { + __map.serialize_entry("messages", &*self.messages)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMessagesResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMessagesResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMessagesResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMessagesResponse"; + } + ::buffa::impl_default_view_instance!(ListMessagesResponseView); + ::buffa::impl_view_reborrow!(ListMessagesResponseView); + /** Self-contained, `'static` owned view of a `ListMessagesResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMessagesResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMessagesResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMessagesResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListMessagesResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMessagesResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMessagesResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMessagesResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMessagesResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListMessagesResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMessagesResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMessagesResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `messages` + #[must_use] + pub fn messages( + &self, + ) -> &::buffa::RepeatedView< + '_, + super::super::__buffa::view::MessageView<'_>, + > { + &self.0.reborrow().messages + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListMessagesResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListMessagesResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMessagesResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListMessagesResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMessagesResponse { + type View<'a> = ListMessagesResponseView<'a>; + type ViewHandle = ListMessagesResponseOwnedView; + } + impl ::serde::Serialize for ListMessagesResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SendMessageRequestView<'a> { + /// Field 1: `conversation_id` + pub conversation_id: &'a str, + /// Field 2: `content` + pub content: &'a str, + /// Field 3: `attachment_upload_id` + pub attachment_upload_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SendMessageRequestView<'a> { + type Owned = super::super::SendMessageRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.conversation_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.content = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.attachment_upload_id = ::buffa::types::borrow_str( + &mut cur, + )?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SendMessageRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SendMessageRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SendMessageRequest { + conversation_id: self.conversation_id.to_string(), + content: self.content.to_string(), + attachment_upload_id: self.attachment_upload_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SendMessageRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.conversation_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.conversation_id) + as u64; + } + if !self.content.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.content) as u64; + } + if !self.attachment_upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len( + &self.attachment_upload_id, + ) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.conversation_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.conversation_id, buf); + } + if !self.content.is_empty() { + ::buffa::types::put_string_field(2u32, &self.content, buf); + } + if !self.attachment_upload_id.is_empty() { + ::buffa::types::put_string_field( + 3u32, + &self.attachment_upload_id, + buf, + ); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SendMessageRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.conversation_id) { + __map.serialize_entry("conversationId", self.conversation_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.content) { + __map.serialize_entry("content", self.content)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str( + self.attachment_upload_id, + ) { + __map + .serialize_entry( + "attachmentUploadId", + self.attachment_upload_id, + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SendMessageRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SendMessageRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.SendMessageRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendMessageRequest"; + } + ::buffa::impl_default_view_instance!(SendMessageRequestView); + ::buffa::impl_view_reborrow!(SendMessageRequestView); + /** Self-contained, `'static` owned view of a `SendMessageRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`SendMessageRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SendMessageRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SendMessageRequestOwnedView( + ::buffa::OwnedView>, + ); + impl SendMessageRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendMessageRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendMessageRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SendMessageRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendMessageRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SendMessageRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SendMessageRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SendMessageRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `conversation_id` + #[must_use] + pub fn conversation_id(&self) -> &'_ str { + self.0.reborrow().conversation_id + } + /// Field 2: `content` + #[must_use] + pub fn content(&self) -> &'_ str { + self.0.reborrow().content + } + /// Field 3: `attachment_upload_id` + #[must_use] + pub fn attachment_upload_id(&self) -> &'_ str { + self.0.reborrow().attachment_upload_id + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SendMessageRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SendMessageRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SendMessageRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SendMessageRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SendMessageRequest { + type View<'a> = SendMessageRequestView<'a>; + type ViewHandle = SendMessageRequestOwnedView; + } + impl ::serde::Serialize for SendMessageRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SendMessageResponseView<'a> { + /// Field 1: `message` + pub message: ::buffa::MessageFieldView< + super::super::__buffa::view::MessageView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SendMessageResponseView<'a> { + type Owned = super::super::SendMessageResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.message.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.message = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::SendMessageResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::SendMessageResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::SendMessageResponse { + message: match self.message.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Message, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SendMessageResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.message.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.message.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.message.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.message.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SendMessageResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.message.as_option() { + __map.serialize_entry("message", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SendMessageResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "SendMessageResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.SendMessageResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.SendMessageResponse"; + } + ::buffa::impl_default_view_instance!(SendMessageResponseView); + ::buffa::impl_view_reborrow!(SendMessageResponseView); + /** Self-contained, `'static` owned view of a `SendMessageResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`SendMessageResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SendMessageResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SendMessageResponseOwnedView( + ::buffa::OwnedView>, + ); + impl SendMessageResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendMessageResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendMessageResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::SendMessageResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SendMessageResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SendMessageResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SendMessageResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SendMessageResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `message` + #[must_use] + pub fn message( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::MessageView<'_>, + > { + &self.0.reborrow().message + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SendMessageResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + SendMessageResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SendMessageResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SendMessageResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::SendMessageResponse { + type View<'a> = SendMessageResponseView<'a>; + type ViewHandle = SendMessageResponseOwnedView; + } + impl ::serde::Serialize for SendMessageResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct MarkMessagesReadRequestView<'a> { + /// Field 1: `conversation_id` + pub conversation_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for MarkMessagesReadRequestView<'a> { + type Owned = super::super::MarkMessagesReadRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.conversation_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::MarkMessagesReadRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::MarkMessagesReadRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::MarkMessagesReadRequest { + conversation_id: self.conversation_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for MarkMessagesReadRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.conversation_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.conversation_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.conversation_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.conversation_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for MarkMessagesReadRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.conversation_id) { + __map.serialize_entry("conversationId", self.conversation_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for MarkMessagesReadRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkMessagesReadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkMessagesReadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkMessagesReadRequest"; + } + ::buffa::impl_default_view_instance!(MarkMessagesReadRequestView); + ::buffa::impl_view_reborrow!(MarkMessagesReadRequestView); + /** Self-contained, `'static` owned view of a `MarkMessagesReadRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`MarkMessagesReadRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`MarkMessagesReadRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct MarkMessagesReadRequestOwnedView( + ::buffa::OwnedView>, + ); + impl MarkMessagesReadRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkMessagesReadRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkMessagesReadRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::MarkMessagesReadRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkMessagesReadRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`MarkMessagesReadRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &MarkMessagesReadRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::MarkMessagesReadRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `conversation_id` + #[must_use] + pub fn conversation_id(&self) -> &'_ str { + self.0.reborrow().conversation_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for MarkMessagesReadRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + MarkMessagesReadRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: MarkMessagesReadRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for MarkMessagesReadRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::MarkMessagesReadRequest { + type View<'a> = MarkMessagesReadRequestView<'a>; + type ViewHandle = MarkMessagesReadRequestOwnedView; + } + impl ::serde::Serialize for MarkMessagesReadRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct MarkMessagesReadResponseView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for MarkMessagesReadResponseView<'a> { + type Owned = super::super::MarkMessagesReadResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::MarkMessagesReadResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::MarkMessagesReadResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::MarkMessagesReadResponse { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for MarkMessagesReadResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for MarkMessagesReadResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for MarkMessagesReadResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkMessagesReadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkMessagesReadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkMessagesReadResponse"; + } + ::buffa::impl_default_view_instance!(MarkMessagesReadResponseView); + ::buffa::impl_view_reborrow!(MarkMessagesReadResponseView); + /** Self-contained, `'static` owned view of a `MarkMessagesReadResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`MarkMessagesReadResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`MarkMessagesReadResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct MarkMessagesReadResponseOwnedView( + ::buffa::OwnedView>, + ); + impl MarkMessagesReadResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkMessagesReadResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkMessagesReadResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::MarkMessagesReadResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkMessagesReadResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`MarkMessagesReadResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &MarkMessagesReadResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::MarkMessagesReadResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for MarkMessagesReadResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + MarkMessagesReadResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: MarkMessagesReadResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for MarkMessagesReadResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::MarkMessagesReadResponse { + type View<'a> = MarkMessagesReadResponseView<'a>; + type ViewHandle = MarkMessagesReadResponseOwnedView; + } + impl ::serde::Serialize for MarkMessagesReadResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Server-streamed conversation events for real-time updates. + #[derive(Clone, Debug, Default)] + pub struct StreamConversationsRequestView<'a> { + /// Client cursor: only events for changes after this timestamp are sent. + /// + /// Field 1: `since` + pub since: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for StreamConversationsRequestView<'a> { + type Owned = super::super::StreamConversationsRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.since.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.since = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::StreamConversationsRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::StreamConversationsRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::StreamConversationsRequest { + since: match self.since.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for StreamConversationsRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.since.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.since.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.since.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.since.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for StreamConversationsRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.since.as_option() { + __map.serialize_entry("since", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for StreamConversationsRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "StreamConversationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.StreamConversationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamConversationsRequest"; + } + ::buffa::impl_default_view_instance!(StreamConversationsRequestView); + ::buffa::impl_view_reborrow!(StreamConversationsRequestView); + /** Self-contained, `'static` owned view of a `StreamConversationsRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`StreamConversationsRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`StreamConversationsRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct StreamConversationsRequestOwnedView( + ::buffa::OwnedView>, + ); + impl StreamConversationsRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamConversationsRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamConversationsRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::StreamConversationsRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamConversationsRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`StreamConversationsRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &StreamConversationsRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::StreamConversationsRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Client cursor: only events for changes after this timestamp are sent. + /// + /// Field 1: `since` + #[must_use] + pub fn since( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().since + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for StreamConversationsRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + StreamConversationsRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: StreamConversationsRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for StreamConversationsRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::StreamConversationsRequest { + type View<'a> = StreamConversationsRequestView<'a>; + type ViewHandle = StreamConversationsRequestOwnedView; + } + impl ::serde::Serialize for StreamConversationsRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct StreamConversationsResponseView<'a> { + pub event: ::core::option::Option< + super::super::__buffa::view::oneof::stream_conversations_response::Event< + 'a, + >, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for StreamConversationsResponseView<'a> { + type Owned = super::super::StreamConversationsResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + if let Some( + super::super::__buffa::view::oneof::stream_conversations_response::Event::Upserted( + ref mut existing, + ), + ) = view.event + { + ::buffa::MessageView::merge_into_view( + &mut **existing, + sub, + __sub_ctx, + )?; + } else { + view.event = Some( + super::super::__buffa::view::oneof::stream_conversations_response::Event::Upserted( + ::buffa::alloc::boxed::Box::new( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ), + ), + ); + } + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + if let Some( + super::super::__buffa::view::oneof::stream_conversations_response::Event::MessageCreated( + ref mut existing, + ), + ) = view.event + { + ::buffa::MessageView::merge_into_view( + &mut **existing, + sub, + __sub_ctx, + )?; + } else { + view.event = Some( + super::super::__buffa::view::oneof::stream_conversations_response::Event::MessageCreated( + ::buffa::alloc::boxed::Box::new( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ), + ), + ); + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::StreamConversationsResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::StreamConversationsResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::StreamConversationsResponse { + event: match self.event.as_ref() { + ::core::option::Option::Some(v) => { + ::core::option::Option::Some( + match v { + super::super::__buffa::view::oneof::stream_conversations_response::Event::Upserted( + v, + ) => { + super::super::__buffa::oneof::stream_conversations_response::Event::Upserted( + ::buffa::alloc::boxed::Box::new( + v.to_owned_from_source(__buffa_src)?, + ), + ) + } + super::super::__buffa::view::oneof::stream_conversations_response::Event::MessageCreated( + v, + ) => { + super::super::__buffa::oneof::stream_conversations_response::Event::MessageCreated( + ::buffa::alloc::boxed::Box::new( + v.to_owned_from_source(__buffa_src)?, + ), + ) + } + }, + ) + } + ::core::option::Option::None => ::core::option::Option::None, + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for StreamConversationsResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if let ::core::option::Option::Some(ref v) = self.event { + match v { + super::super::__buffa::view::oneof::stream_conversations_response::Event::Upserted( + x, + ) => { + let __slot = __cache.reserve(); + let inner = x.compute_size(__cache); + __cache.set(__slot, inner); + size + += 1u64 + ::buffa::encoding::varint_len(inner as u64) as u64 + + inner as u64; + } + super::super::__buffa::view::oneof::stream_conversations_response::Event::MessageCreated( + x, + ) => { + let __slot = __cache.reserve(); + let inner = x.compute_size(__cache); + __cache.set(__slot, inner); + size + += 1u64 + ::buffa::encoding::varint_len(inner as u64) as u64 + + inner as u64; + } + } + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let ::core::option::Option::Some(ref v) = self.event { + match v { + super::super::__buffa::view::oneof::stream_conversations_response::Event::Upserted( + x, + ) => { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + x.write_to(__cache, buf); + } + super::super::__buffa::view::oneof::stream_conversations_response::Event::MessageCreated( + x, + ) => { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + x.write_to(__cache, buf); + } + } + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for StreamConversationsResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if let ::core::option::Option::Some(ref __ov) = self.event { + match __ov { + super::super::__buffa::view::oneof::stream_conversations_response::Event::Upserted( + v, + ) => { + __map.serialize_entry("upserted", v)?; + } + super::super::__buffa::view::oneof::stream_conversations_response::Event::MessageCreated( + v, + ) => { + __map.serialize_entry("messageCreated", v)?; + } + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for StreamConversationsResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "StreamConversationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.StreamConversationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamConversationsResponse"; + } + ::buffa::impl_default_view_instance!(StreamConversationsResponseView); + ::buffa::impl_view_reborrow!(StreamConversationsResponseView); + /** Self-contained, `'static` owned view of a `StreamConversationsResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`StreamConversationsResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`StreamConversationsResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct StreamConversationsResponseOwnedView( + ::buffa::OwnedView>, + ); + impl StreamConversationsResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamConversationsResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamConversationsResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::StreamConversationsResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamConversationsResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`StreamConversationsResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &StreamConversationsResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::StreamConversationsResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Oneof `event`. + #[must_use] + pub fn event( + &self, + ) -> ::core::option::Option< + &super::super::__buffa::view::oneof::stream_conversations_response::Event< + '_, + >, + > { + self.0.reborrow().event.as_ref() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for StreamConversationsResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + StreamConversationsResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: StreamConversationsResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for StreamConversationsResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::StreamConversationsResponse { + type View<'a> = StreamConversationsResponseView<'a>; + type ViewHandle = StreamConversationsResponseOwnedView; + } + impl ::serde::Serialize for StreamConversationsResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to the meetup_locations table. + #[derive(Clone, Debug, Default)] + pub struct MeetupLocationView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `name` + pub name: &'a str, + /// Field 3: `description` + pub description: &'a str, + /// Field 4: `verified` + pub verified: bool, + /// Field 5: `location` + pub location: ::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'a>, + >, + /// Field 6: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for MeetupLocationView<'a> { + type Owned = super::super::MeetupLocation; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.name = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.description = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.verified = ::buffa::types::decode_bool(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.location.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.location = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::MeetupLocation, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::MeetupLocation, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::MeetupLocation { + id: self.id.to_string(), + name: self.name.to_string(), + description: self.description.to_string(), + verified: self.verified, + location: match self.location.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::LatLng, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for MeetupLocationView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.name.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.name) as u64; + } + if !self.description.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.description) + as u64; + } + if self.verified { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.name.is_empty() { + ::buffa::types::put_string_field(2u32, &self.name, buf); + } + if !self.description.is_empty() { + ::buffa::types::put_string_field(3u32, &self.description, buf); + } + if self.verified { + ::buffa::types::put_bool_field(4u32, self.verified, buf); + } + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for MeetupLocationView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.name) { + __map.serialize_entry("name", self.name)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.description) { + __map.serialize_entry("description", self.description)?; + } + if self.verified { + __map.serialize_entry("verified", &self.verified)?; + } + { + if let ::core::option::Option::Some(__v) = self.location.as_option() + { + __map.serialize_entry("location", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for MeetupLocationView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MeetupLocation"; + const FULL_NAME: &'static str = "bookbridge.v1.MeetupLocation"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MeetupLocation"; + } + ::buffa::impl_default_view_instance!(MeetupLocationView); + ::buffa::impl_view_reborrow!(MeetupLocationView); + /** Self-contained, `'static` owned view of a `MeetupLocation` message. + + Wraps [`::buffa::OwnedView`]`<`[`MeetupLocationView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`MeetupLocationView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct MeetupLocationOwnedView( + ::buffa::OwnedView>, + ); + impl MeetupLocationOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MeetupLocationOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MeetupLocationOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::MeetupLocation, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MeetupLocationOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`MeetupLocationView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &MeetupLocationView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::MeetupLocation { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `name` + #[must_use] + pub fn name(&self) -> &'_ str { + self.0.reborrow().name + } + /// Field 3: `description` + #[must_use] + pub fn description(&self) -> &'_ str { + self.0.reborrow().description + } + /// Field 4: `verified` + #[must_use] + pub fn verified(&self) -> bool { + self.0.reborrow().verified + } + /// Field 5: `location` + #[must_use] + pub fn location( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'_>, + > { + &self.0.reborrow().location + } + /// Field 6: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for MeetupLocationOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + MeetupLocationOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: MeetupLocationOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for MeetupLocationOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::MeetupLocation { + type View<'a> = MeetupLocationView<'a>; + type ViewHandle = MeetupLocationOwnedView; + } + impl ::serde::Serialize for MeetupLocationOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMeetupLocationsRequestView<'a> { + /// When set, only return locations within radius of the center. + /// + /// Field 1: `center` + pub center: ::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'a>, + >, + /// Field 2: `radius_km` + pub radius_km: f64, + /// Field 3: `page_token` + pub page_token: &'a str, + /// Field 4: `page_size` + pub page_size: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMeetupLocationsRequestView<'a> { + type Owned = super::super::ListMeetupLocationsRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.center.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.center = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + view.radius_km = ::buffa::types::decode_double(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMeetupLocationsRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMeetupLocationsRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMeetupLocationsRequest { + center: match self.center.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::LatLng, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + radius_km: self.radius_km, + page_token: self.page_token.to_string(), + page_size: self.page_size, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMeetupLocationsRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.center.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.center.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.radius_km.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.center.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.center.write_to(__cache, buf); + } + if self.radius_km.to_bits() != 0u64 { + ::buffa::types::put_double_field(2u32, self.radius_km, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(3u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(4u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMeetupLocationsRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.center.as_option() { + __map.serialize_entry("center", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_zero_f64(&self.radius_km) { + __map + .serialize_entry( + "radiusKm", + &::buffa::json_helpers::ProtoJson(&self.radius_km), + )?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMeetupLocationsRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMeetupLocationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMeetupLocationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMeetupLocationsRequest"; + } + ::buffa::impl_default_view_instance!(ListMeetupLocationsRequestView); + ::buffa::impl_view_reborrow!(ListMeetupLocationsRequestView); + /** Self-contained, `'static` owned view of a `ListMeetupLocationsRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMeetupLocationsRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMeetupLocationsRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMeetupLocationsRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListMeetupLocationsRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMeetupLocationsRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMeetupLocationsRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMeetupLocationsRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMeetupLocationsRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListMeetupLocationsRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMeetupLocationsRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMeetupLocationsRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// When set, only return locations within radius of the center. + /// + /// Field 1: `center` + #[must_use] + pub fn center( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::LatLngView<'_>, + > { + &self.0.reborrow().center + } + /// Field 2: `radius_km` + #[must_use] + pub fn radius_km(&self) -> f64 { + self.0.reborrow().radius_km + } + /// Field 3: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 4: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListMeetupLocationsRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListMeetupLocationsRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMeetupLocationsRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListMeetupLocationsRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMeetupLocationsRequest { + type View<'a> = ListMeetupLocationsRequestView<'a>; + type ViewHandle = ListMeetupLocationsRequestOwnedView; + } + impl ::serde::Serialize for ListMeetupLocationsRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMeetupLocationsResponseView<'a> { + /// Field 1: `locations` + pub locations: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::MeetupLocationView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMeetupLocationsResponseView<'a> { + type Owned = super::super::ListMeetupLocationsResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::MeetupLocationView, + >(), + )?; + view.locations + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMeetupLocationsResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMeetupLocationsResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMeetupLocationsResponse { + locations: self + .locations + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMeetupLocationsResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.locations { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.locations { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMeetupLocationsResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.locations.is_empty() { + __map.serialize_entry("locations", &*self.locations)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMeetupLocationsResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMeetupLocationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMeetupLocationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMeetupLocationsResponse"; + } + ::buffa::impl_default_view_instance!(ListMeetupLocationsResponseView); + ::buffa::impl_view_reborrow!(ListMeetupLocationsResponseView); + /** Self-contained, `'static` owned view of a `ListMeetupLocationsResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMeetupLocationsResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMeetupLocationsResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMeetupLocationsResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListMeetupLocationsResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMeetupLocationsResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMeetupLocationsResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMeetupLocationsResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMeetupLocationsResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListMeetupLocationsResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMeetupLocationsResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMeetupLocationsResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `locations` + #[must_use] + pub fn locations( + &self, + ) -> &::buffa::RepeatedView< + '_, + super::super::__buffa::view::MeetupLocationView<'_>, + > { + &self.0.reborrow().locations + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListMeetupLocationsResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListMeetupLocationsResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMeetupLocationsResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListMeetupLocationsResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMeetupLocationsResponse { + type View<'a> = ListMeetupLocationsResponseView<'a>; + type ViewHandle = ListMeetupLocationsResponseOwnedView; + } + impl ::serde::Serialize for ListMeetupLocationsResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetMeetupLocationRequestView<'a> { + /// Field 1: `location_id` + pub location_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetMeetupLocationRequestView<'a> { + type Owned = super::super::GetMeetupLocationRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.location_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetMeetupLocationRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetMeetupLocationRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetMeetupLocationRequest { + location_id: self.location_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetMeetupLocationRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.location_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.location_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.location_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.location_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetMeetupLocationRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.location_id) { + __map.serialize_entry("locationId", self.location_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetMeetupLocationRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetMeetupLocationRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetMeetupLocationRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetMeetupLocationRequest"; + } + ::buffa::impl_default_view_instance!(GetMeetupLocationRequestView); + ::buffa::impl_view_reborrow!(GetMeetupLocationRequestView); + /** Self-contained, `'static` owned view of a `GetMeetupLocationRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetMeetupLocationRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetMeetupLocationRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetMeetupLocationRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetMeetupLocationRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetMeetupLocationRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetMeetupLocationRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetMeetupLocationRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetMeetupLocationRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`GetMeetupLocationRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetMeetupLocationRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetMeetupLocationRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `location_id` + #[must_use] + pub fn location_id(&self) -> &'_ str { + self.0.reborrow().location_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetMeetupLocationRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetMeetupLocationRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetMeetupLocationRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetMeetupLocationRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetMeetupLocationRequest { + type View<'a> = GetMeetupLocationRequestView<'a>; + type ViewHandle = GetMeetupLocationRequestOwnedView; + } + impl ::serde::Serialize for GetMeetupLocationRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetMeetupLocationResponseView<'a> { + /// Field 1: `location` + pub location: ::buffa::MessageFieldView< + super::super::__buffa::view::MeetupLocationView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetMeetupLocationResponseView<'a> { + type Owned = super::super::GetMeetupLocationResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.location.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.location = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetMeetupLocationResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetMeetupLocationResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetMeetupLocationResponse { + location: match self.location.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::MeetupLocation, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetMeetupLocationResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.location.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.location.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetMeetupLocationResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.location.as_option() + { + __map.serialize_entry("location", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetMeetupLocationResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetMeetupLocationResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetMeetupLocationResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetMeetupLocationResponse"; + } + ::buffa::impl_default_view_instance!(GetMeetupLocationResponseView); + ::buffa::impl_view_reborrow!(GetMeetupLocationResponseView); + /** Self-contained, `'static` owned view of a `GetMeetupLocationResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetMeetupLocationResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetMeetupLocationResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetMeetupLocationResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetMeetupLocationResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetMeetupLocationResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetMeetupLocationResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetMeetupLocationResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetMeetupLocationResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`GetMeetupLocationResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetMeetupLocationResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetMeetupLocationResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `location` + #[must_use] + pub fn location( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::MeetupLocationView<'_>, + > { + &self.0.reborrow().location + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetMeetupLocationResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetMeetupLocationResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetMeetupLocationResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetMeetupLocationResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetMeetupLocationResponse { + type View<'a> = GetMeetupLocationResponseView<'a>; + type ViewHandle = GetMeetupLocationResponseOwnedView; + } + impl ::serde::Serialize for GetMeetupLocationResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to notifications joined with notification_bodies / template translations. + #[derive(Clone, Debug, Default)] + pub struct NotificationView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `title` + pub title: &'a str, + /// Field 3: `body` + pub body: &'a str, + /// Field 4: `type` + pub r#type: &'a str, + /// Field 5: `data` + pub data: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::StructView<'a>, + >, + /// Field 6: `read_at` + pub read_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 7: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for NotificationView<'a> { + type Owned = super::super::Notification; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.title = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.body = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.r#type = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.data.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.data = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::StructView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.read_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.read_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::Notification, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::Notification, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Notification { + id: self.id.to_string(), + title: self.title.to_string(), + body: self.body.to_string(), + r#type: self.r#type.to_string(), + data: match self.data.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Struct, + ::buffa::Inline<::buffa_types::google::protobuf::Struct>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + read_at: match self.read_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for NotificationView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.title.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.body.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.body) as u64; + } + if !self.r#type.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.r#type) as u64; + } + if self.data.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.data.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.read_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.read_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.title.is_empty() { + ::buffa::types::put_string_field(2u32, &self.title, buf); + } + if !self.body.is_empty() { + ::buffa::types::put_string_field(3u32, &self.body, buf); + } + if !self.r#type.is_empty() { + ::buffa::types::put_string_field(4u32, &self.r#type, buf); + } + if self.data.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.data.write_to(__cache, buf); + } + if self.read_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.read_at.write_to(__cache, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 7u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for NotificationView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.title) { + __map.serialize_entry("title", self.title)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.body) { + __map.serialize_entry("body", self.body)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.r#type) { + __map.serialize_entry("type", self.r#type)?; + } + { + if let ::core::option::Option::Some(__v) = self.data.as_option() { + __map.serialize_entry("data", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self.read_at.as_option() { + __map.serialize_entry("readAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for NotificationView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Notification"; + const FULL_NAME: &'static str = "bookbridge.v1.Notification"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Notification"; + } + ::buffa::impl_default_view_instance!(NotificationView); + ::buffa::impl_view_reborrow!(NotificationView); + /** Self-contained, `'static` owned view of a `Notification` message. + + Wraps [`::buffa::OwnedView`]`<`[`NotificationView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`NotificationView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct NotificationOwnedView(::buffa::OwnedView>); + impl NotificationOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + NotificationOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + NotificationOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Notification, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + NotificationOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`NotificationView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &NotificationView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Notification { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `title` + #[must_use] + pub fn title(&self) -> &'_ str { + self.0.reborrow().title + } + /// Field 3: `body` + #[must_use] + pub fn body(&self) -> &'_ str { + self.0.reborrow().body + } + /// Field 4: `type` + #[must_use] + pub fn r#type(&self) -> &'_ str { + self.0.reborrow().r#type + } + /// Field 5: `data` + #[must_use] + pub fn data( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::StructView<'_>, + > { + &self.0.reborrow().data + } + /// Field 6: `read_at` + #[must_use] + pub fn read_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().read_at + } + /// Field 7: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for NotificationOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + NotificationOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: NotificationOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for NotificationOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Notification { + type View<'a> = NotificationView<'a>; + type ViewHandle = NotificationOwnedView; + } + impl ::serde::Serialize for NotificationOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListNotificationsRequestView<'a> { + /// Field 1: `page_token` + pub page_token: &'a str, + /// Field 2: `page_size` + pub page_size: i32, + /// Field 3: `unread_only` + pub unread_only: bool, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListNotificationsRequestView<'a> { + type Owned = super::super::ListNotificationsRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.unread_only = ::buffa::types::decode_bool(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListNotificationsRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListNotificationsRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListNotificationsRequest { + page_token: self.page_token.to_string(), + page_size: self.page_size, + unread_only: self.unread_only, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListNotificationsRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + if self.unread_only { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + if self.unread_only { + ::buffa::types::put_bool_field(3u32, self.unread_only, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListNotificationsRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + if self.unread_only { + __map.serialize_entry("unreadOnly", &self.unread_only)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListNotificationsRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListNotificationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListNotificationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListNotificationsRequest"; + } + ::buffa::impl_default_view_instance!(ListNotificationsRequestView); + ::buffa::impl_view_reborrow!(ListNotificationsRequestView); + /** Self-contained, `'static` owned view of a `ListNotificationsRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListNotificationsRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListNotificationsRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListNotificationsRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListNotificationsRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListNotificationsRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListNotificationsRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListNotificationsRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListNotificationsRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListNotificationsRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListNotificationsRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListNotificationsRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 2: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + /// Field 3: `unread_only` + #[must_use] + pub fn unread_only(&self) -> bool { + self.0.reborrow().unread_only + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListNotificationsRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListNotificationsRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListNotificationsRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListNotificationsRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListNotificationsRequest { + type View<'a> = ListNotificationsRequestView<'a>; + type ViewHandle = ListNotificationsRequestOwnedView; + } + impl ::serde::Serialize for ListNotificationsRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListNotificationsResponseView<'a> { + /// Field 1: `notifications` + pub notifications: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::NotificationView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListNotificationsResponseView<'a> { + type Owned = super::super::ListNotificationsResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::NotificationView, + >(), + )?; + view.notifications + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListNotificationsResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListNotificationsResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListNotificationsResponse { + notifications: self + .notifications + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListNotificationsResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.notifications { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.notifications { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListNotificationsResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.notifications.is_empty() { + __map.serialize_entry("notifications", &*self.notifications)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListNotificationsResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListNotificationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListNotificationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListNotificationsResponse"; + } + ::buffa::impl_default_view_instance!(ListNotificationsResponseView); + ::buffa::impl_view_reborrow!(ListNotificationsResponseView); + /** Self-contained, `'static` owned view of a `ListNotificationsResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListNotificationsResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListNotificationsResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListNotificationsResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListNotificationsResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListNotificationsResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListNotificationsResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListNotificationsResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListNotificationsResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListNotificationsResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListNotificationsResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListNotificationsResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `notifications` + #[must_use] + pub fn notifications( + &self, + ) -> &::buffa::RepeatedView< + '_, + super::super::__buffa::view::NotificationView<'_>, + > { + &self.0.reborrow().notifications + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListNotificationsResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListNotificationsResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListNotificationsResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListNotificationsResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListNotificationsResponse { + type View<'a> = ListNotificationsResponseView<'a>; + type ViewHandle = ListNotificationsResponseOwnedView; + } + impl ::serde::Serialize for ListNotificationsResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct MarkNotificationReadRequestView<'a> { + /// Field 1: `notification_id` + pub notification_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for MarkNotificationReadRequestView<'a> { + type Owned = super::super::MarkNotificationReadRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.notification_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::MarkNotificationReadRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::MarkNotificationReadRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::MarkNotificationReadRequest { + notification_id: self.notification_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for MarkNotificationReadRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.notification_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.notification_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.notification_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.notification_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for MarkNotificationReadRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.notification_id) { + __map.serialize_entry("notificationId", self.notification_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for MarkNotificationReadRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkNotificationReadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkNotificationReadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkNotificationReadRequest"; + } + ::buffa::impl_default_view_instance!(MarkNotificationReadRequestView); + ::buffa::impl_view_reborrow!(MarkNotificationReadRequestView); + /** Self-contained, `'static` owned view of a `MarkNotificationReadRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`MarkNotificationReadRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`MarkNotificationReadRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct MarkNotificationReadRequestOwnedView( + ::buffa::OwnedView>, + ); + impl MarkNotificationReadRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkNotificationReadRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkNotificationReadRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::MarkNotificationReadRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkNotificationReadRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`MarkNotificationReadRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &MarkNotificationReadRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::MarkNotificationReadRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `notification_id` + #[must_use] + pub fn notification_id(&self) -> &'_ str { + self.0.reborrow().notification_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for MarkNotificationReadRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + MarkNotificationReadRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: MarkNotificationReadRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for MarkNotificationReadRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::MarkNotificationReadRequest { + type View<'a> = MarkNotificationReadRequestView<'a>; + type ViewHandle = MarkNotificationReadRequestOwnedView; + } + impl ::serde::Serialize for MarkNotificationReadRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct MarkNotificationReadResponseView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for MarkNotificationReadResponseView<'a> { + type Owned = super::super::MarkNotificationReadResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::MarkNotificationReadResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::MarkNotificationReadResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::MarkNotificationReadResponse { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for MarkNotificationReadResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for MarkNotificationReadResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for MarkNotificationReadResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkNotificationReadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkNotificationReadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkNotificationReadResponse"; + } + ::buffa::impl_default_view_instance!(MarkNotificationReadResponseView); + ::buffa::impl_view_reborrow!(MarkNotificationReadResponseView); + /** Self-contained, `'static` owned view of a `MarkNotificationReadResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`MarkNotificationReadResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`MarkNotificationReadResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct MarkNotificationReadResponseOwnedView( + ::buffa::OwnedView>, + ); + impl MarkNotificationReadResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkNotificationReadResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkNotificationReadResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::MarkNotificationReadResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkNotificationReadResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`MarkNotificationReadResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &MarkNotificationReadResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::MarkNotificationReadResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for MarkNotificationReadResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + MarkNotificationReadResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: MarkNotificationReadResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for MarkNotificationReadResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::MarkNotificationReadResponse { + type View<'a> = MarkNotificationReadResponseView<'a>; + type ViewHandle = MarkNotificationReadResponseOwnedView; + } + impl ::serde::Serialize for MarkNotificationReadResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct MarkAllNotificationsReadRequestView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for MarkAllNotificationsReadRequestView<'a> { + type Owned = super::super::MarkAllNotificationsReadRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::MarkAllNotificationsReadRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::MarkAllNotificationsReadRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::MarkAllNotificationsReadRequest { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for MarkAllNotificationsReadRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for MarkAllNotificationsReadRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for MarkAllNotificationsReadRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkAllNotificationsReadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkAllNotificationsReadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkAllNotificationsReadRequest"; + } + ::buffa::impl_default_view_instance!(MarkAllNotificationsReadRequestView); + ::buffa::impl_view_reborrow!(MarkAllNotificationsReadRequestView); + /** Self-contained, `'static` owned view of a `MarkAllNotificationsReadRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`MarkAllNotificationsReadRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`MarkAllNotificationsReadRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct MarkAllNotificationsReadRequestOwnedView( + ::buffa::OwnedView>, + ); + impl MarkAllNotificationsReadRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkAllNotificationsReadRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkAllNotificationsReadRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::MarkAllNotificationsReadRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkAllNotificationsReadRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`MarkAllNotificationsReadRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &MarkAllNotificationsReadRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::MarkAllNotificationsReadRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for MarkAllNotificationsReadRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + MarkAllNotificationsReadRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: MarkAllNotificationsReadRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for MarkAllNotificationsReadRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::MarkAllNotificationsReadRequest { + type View<'a> = MarkAllNotificationsReadRequestView<'a>; + type ViewHandle = MarkAllNotificationsReadRequestOwnedView; + } + impl ::serde::Serialize for MarkAllNotificationsReadRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct MarkAllNotificationsReadResponseView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for MarkAllNotificationsReadResponseView<'a> { + type Owned = super::super::MarkAllNotificationsReadResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::MarkAllNotificationsReadResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::MarkAllNotificationsReadResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::MarkAllNotificationsReadResponse { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for MarkAllNotificationsReadResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for MarkAllNotificationsReadResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for MarkAllNotificationsReadResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "MarkAllNotificationsReadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.MarkAllNotificationsReadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.MarkAllNotificationsReadResponse"; + } + ::buffa::impl_default_view_instance!(MarkAllNotificationsReadResponseView); + ::buffa::impl_view_reborrow!(MarkAllNotificationsReadResponseView); + /** Self-contained, `'static` owned view of a `MarkAllNotificationsReadResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`MarkAllNotificationsReadResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`MarkAllNotificationsReadResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct MarkAllNotificationsReadResponseOwnedView( + ::buffa::OwnedView>, + ); + impl MarkAllNotificationsReadResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkAllNotificationsReadResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkAllNotificationsReadResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::MarkAllNotificationsReadResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + MarkAllNotificationsReadResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`MarkAllNotificationsReadResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &MarkAllNotificationsReadResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::MarkAllNotificationsReadResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for MarkAllNotificationsReadResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + MarkAllNotificationsReadResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: MarkAllNotificationsReadResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for MarkAllNotificationsReadResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::MarkAllNotificationsReadResponse { + type View<'a> = MarkAllNotificationsReadResponseView<'a>; + type ViewHandle = MarkAllNotificationsReadResponseOwnedView; + } + impl ::serde::Serialize for MarkAllNotificationsReadResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Server-streamed notifications for real-time updates. + #[derive(Clone, Debug, Default)] + pub struct StreamNotificationsRequestView<'a> { + /// Field 1: `since` + pub since: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for StreamNotificationsRequestView<'a> { + type Owned = super::super::StreamNotificationsRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.since.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.since = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::StreamNotificationsRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::StreamNotificationsRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::StreamNotificationsRequest { + since: match self.since.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for StreamNotificationsRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.since.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.since.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.since.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.since.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for StreamNotificationsRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.since.as_option() { + __map.serialize_entry("since", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for StreamNotificationsRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "StreamNotificationsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.StreamNotificationsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamNotificationsRequest"; + } + ::buffa::impl_default_view_instance!(StreamNotificationsRequestView); + ::buffa::impl_view_reborrow!(StreamNotificationsRequestView); + /** Self-contained, `'static` owned view of a `StreamNotificationsRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`StreamNotificationsRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`StreamNotificationsRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct StreamNotificationsRequestOwnedView( + ::buffa::OwnedView>, + ); + impl StreamNotificationsRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamNotificationsRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamNotificationsRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::StreamNotificationsRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamNotificationsRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`StreamNotificationsRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &StreamNotificationsRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::StreamNotificationsRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `since` + #[must_use] + pub fn since( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().since + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for StreamNotificationsRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + StreamNotificationsRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: StreamNotificationsRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for StreamNotificationsRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::StreamNotificationsRequest { + type View<'a> = StreamNotificationsRequestView<'a>; + type ViewHandle = StreamNotificationsRequestOwnedView; + } + impl ::serde::Serialize for StreamNotificationsRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct StreamNotificationsResponseView<'a> { + /// Field 1: `notification` + pub notification: ::buffa::MessageFieldView< + super::super::__buffa::view::NotificationView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for StreamNotificationsResponseView<'a> { + type Owned = super::super::StreamNotificationsResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.notification.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.notification = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::StreamNotificationsResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::StreamNotificationsResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::StreamNotificationsResponse { + notification: match self.notification.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Notification, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for StreamNotificationsResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.notification.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.notification.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.notification.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.notification.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for StreamNotificationsResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self + .notification + .as_option() + { + __map.serialize_entry("notification", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for StreamNotificationsResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "StreamNotificationsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.StreamNotificationsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.StreamNotificationsResponse"; + } + ::buffa::impl_default_view_instance!(StreamNotificationsResponseView); + ::buffa::impl_view_reborrow!(StreamNotificationsResponseView); + /** Self-contained, `'static` owned view of a `StreamNotificationsResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`StreamNotificationsResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`StreamNotificationsResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct StreamNotificationsResponseOwnedView( + ::buffa::OwnedView>, + ); + impl StreamNotificationsResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamNotificationsResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamNotificationsResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::StreamNotificationsResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + StreamNotificationsResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`StreamNotificationsResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &StreamNotificationsResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::StreamNotificationsResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `notification` + #[must_use] + pub fn notification( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::NotificationView<'_>, + > { + &self.0.reborrow().notification + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for StreamNotificationsResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + StreamNotificationsResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: StreamNotificationsResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for StreamNotificationsResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::StreamNotificationsResponse { + type View<'a> = StreamNotificationsResponseView<'a>; + type ViewHandle = StreamNotificationsResponseOwnedView; + } + impl ::serde::Serialize for StreamNotificationsResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to payment_intents + payments. + #[derive(Clone, Debug, Default)] + pub struct PaymentView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `method` + pub method: ::buffa::EnumValue, + /// Field 3: `amount_fcfa` + pub amount_fcfa: i64, + /// Field 4: `status` + pub status: ::buffa::EnumValue, + /// Field 5: `purpose` + pub purpose: ::buffa::EnumValue, + /// Field 6: `platform_transaction_reference` + pub platform_transaction_reference: &'a str, + /// Field 7: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + /// Field 8: `updated_at` + pub updated_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for PaymentView<'a> { + type Owned = super::super::Payment; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.method = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.amount_fcfa = ::buffa::types::decode_int64(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.purpose = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.platform_transaction_reference = ::buffa::types::borrow_str( + &mut cur, + )?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 8u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.updated_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.updated_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Payment { + id: self.id.to_string(), + method: self.method, + amount_fcfa: self.amount_fcfa, + status: self.status, + purpose: self.purpose, + platform_transaction_reference: self + .platform_transaction_reference + .to_string(), + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + updated_at: match self.updated_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for PaymentView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + { + let val = self.method.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.amount_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.amount_fcfa) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + { + let val = self.purpose.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if !self.platform_transaction_reference.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len( + &self.platform_transaction_reference, + ) as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if self.updated_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.updated_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + { + let val = self.method.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(2u32, val, buf); + } + } + if self.amount_fcfa != 0i64 { + ::buffa::types::put_int64_field(3u32, self.amount_fcfa, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(4u32, val, buf); + } + } + { + let val = self.purpose.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(5u32, val, buf); + } + } + if !self.platform_transaction_reference.is_empty() { + ::buffa::types::put_string_field( + 6u32, + &self.platform_transaction_reference, + buf, + ); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 7u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + if self.updated_at.is_set() { + ::buffa::types::put_len_delimited_header( + 8u32, + u64::from(__cache.consume_next()), + buf, + ); + self.updated_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for PaymentView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.method) { + __map.serialize_entry("method", &self.method)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.amount_fcfa) { + __map + .serialize_entry( + "amountFcfa", + &::buffa::json_helpers::ProtoJson(&self.amount_fcfa), + )?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.status) { + __map.serialize_entry("status", &self.status)?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value( + &self.purpose, + ) { + __map.serialize_entry("purpose", &self.purpose)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str( + self.platform_transaction_reference, + ) { + __map + .serialize_entry( + "platformTransactionReference", + self.platform_transaction_reference, + )?; + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self + .updated_at + .as_option() + { + __map.serialize_entry("updatedAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for PaymentView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Payment"; + const FULL_NAME: &'static str = "bookbridge.v1.Payment"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Payment"; + } + ::buffa::impl_default_view_instance!(PaymentView); + ::buffa::impl_view_reborrow!(PaymentView); + /** Self-contained, `'static` owned view of a `Payment` message. + + Wraps [`::buffa::OwnedView`]`<`[`PaymentView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`PaymentView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct PaymentOwnedView(::buffa::OwnedView>); + impl PaymentOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PaymentOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PaymentOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Payment, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PaymentOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`PaymentView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &PaymentView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Payment { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `method` + #[must_use] + pub fn method(&self) -> ::buffa::EnumValue { + self.0.reborrow().method + } + /// Field 3: `amount_fcfa` + #[must_use] + pub fn amount_fcfa(&self) -> i64 { + self.0.reborrow().amount_fcfa + } + /// Field 4: `status` + #[must_use] + pub fn status(&self) -> ::buffa::EnumValue { + self.0.reborrow().status + } + /// Field 5: `purpose` + #[must_use] + pub fn purpose(&self) -> ::buffa::EnumValue { + self.0.reborrow().purpose + } + /// Field 6: `platform_transaction_reference` + #[must_use] + pub fn platform_transaction_reference(&self) -> &'_ str { + self.0.reborrow().platform_transaction_reference + } + /// Field 7: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + /// Field 8: `updated_at` + #[must_use] + pub fn updated_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().updated_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for PaymentOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + PaymentOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: PaymentOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for PaymentOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Payment { + type View<'a> = PaymentView<'a>; + type ViewHandle = PaymentOwnedView; + } + impl ::serde::Serialize for PaymentOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to book_purchases (escrow flow). + #[derive(Clone, Debug, Default)] + pub struct PurchaseView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `transaction_id` + pub transaction_id: &'a str, + /// Field 3: `book` + pub book: ::buffa::MessageFieldView< + super::super::__buffa::view::BookPurchaseDetailsView<'a>, + >, + /// Field 4: `buyer_id` + pub buyer_id: &'a str, + /// Field 5: `status` + pub status: ::buffa::EnumValue, + /// Field 6: `confirmed` + pub confirmed: bool, + /// Field 7: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for PurchaseView<'a> { + type Owned = super::super::Purchase; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.transaction_id = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.book.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.book = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.buyer_id = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.confirmed = ::buffa::types::decode_bool(&mut cur)?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Purchase { + id: self.id.to_string(), + transaction_id: self.transaction_id.to_string(), + book: match self.book.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::BookPurchaseDetails, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + buyer_id: self.buyer_id.to_string(), + status: self.status, + confirmed: self.confirmed, + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for PurchaseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.transaction_id) + as u64; + } + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.buyer_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.buyer_id) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.confirmed { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.transaction_id, buf); + } + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 3u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + if !self.buyer_id.is_empty() { + ::buffa::types::put_string_field(4u32, &self.buyer_id, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(5u32, val, buf); + } + } + if self.confirmed { + ::buffa::types::put_bool_field(6u32, self.confirmed, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 7u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for PurchaseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.transaction_id) { + __map.serialize_entry("transactionId", self.transaction_id)?; + } + { + if let ::core::option::Option::Some(__v) = self.book.as_option() { + __map.serialize_entry("book", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.buyer_id) { + __map.serialize_entry("buyerId", self.buyer_id)?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.status) { + __map.serialize_entry("status", &self.status)?; + } + if self.confirmed { + __map.serialize_entry("confirmed", &self.confirmed)?; + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for PurchaseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Purchase"; + const FULL_NAME: &'static str = "bookbridge.v1.Purchase"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Purchase"; + } + ::buffa::impl_default_view_instance!(PurchaseView); + ::buffa::impl_view_reborrow!(PurchaseView); + /** Self-contained, `'static` owned view of a `Purchase` message. + + Wraps [`::buffa::OwnedView`]`<`[`PurchaseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`PurchaseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct PurchaseOwnedView(::buffa::OwnedView>); + impl PurchaseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PurchaseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PurchaseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Purchase, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PurchaseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`PurchaseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &PurchaseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Purchase { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `transaction_id` + #[must_use] + pub fn transaction_id(&self) -> &'_ str { + self.0.reborrow().transaction_id + } + /// Field 3: `book` + #[must_use] + pub fn book( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::BookPurchaseDetailsView<'_>, + > { + &self.0.reborrow().book + } + /// Field 4: `buyer_id` + #[must_use] + pub fn buyer_id(&self) -> &'_ str { + self.0.reborrow().buyer_id + } + /// Field 5: `status` + #[must_use] + pub fn status(&self) -> ::buffa::EnumValue { + self.0.reborrow().status + } + /// Field 6: `confirmed` + #[must_use] + pub fn confirmed(&self) -> bool { + self.0.reborrow().confirmed + } + /// Field 7: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for PurchaseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + PurchaseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: PurchaseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for PurchaseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Purchase { + type View<'a> = PurchaseView<'a>; + type ViewHandle = PurchaseOwnedView; + } + impl ::serde::Serialize for PurchaseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct BookPurchaseDetailsView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + /// Field 2: `title` + pub title: &'a str, + /// Field 3: `cover_url` + pub cover_url: &'a str, + /// Field 4: `price_fcfa` + pub price_fcfa: i64, + /// Field 5: `meetup_location` + pub meetup_location: ::buffa::MessageFieldView< + super::super::__buffa::view::MeetupLocationView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for BookPurchaseDetailsView<'a> { + type Owned = super::super::BookPurchaseDetails; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.title = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.cover_url = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.price_fcfa = ::buffa::types::decode_int64(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.meetup_location.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.meetup_location = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::BookPurchaseDetails, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::BookPurchaseDetails, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::BookPurchaseDetails { + book_id: self.book_id.to_string(), + title: self.title.to_string(), + cover_url: self.cover_url.to_string(), + price_fcfa: self.price_fcfa, + meetup_location: match self.meetup_location.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::MeetupLocation, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for BookPurchaseDetailsView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if !self.title.is_empty() { + size + += 1u64 + ::buffa::types::string_encoded_len(&self.title) as u64; + } + if !self.cover_url.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.cover_url) as u64; + } + if self.price_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.price_fcfa) as u64; + } + if self.meetup_location.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.meetup_location.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + if !self.title.is_empty() { + ::buffa::types::put_string_field(2u32, &self.title, buf); + } + if !self.cover_url.is_empty() { + ::buffa::types::put_string_field(3u32, &self.cover_url, buf); + } + if self.price_fcfa != 0i64 { + ::buffa::types::put_int64_field(4u32, self.price_fcfa, buf); + } + if self.meetup_location.is_set() { + ::buffa::types::put_len_delimited_header( + 5u32, + u64::from(__cache.consume_next()), + buf, + ); + self.meetup_location.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for BookPurchaseDetailsView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.title) { + __map.serialize_entry("title", self.title)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.cover_url) { + __map.serialize_entry("coverUrl", self.cover_url)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.price_fcfa) { + __map + .serialize_entry( + "priceFcfa", + &::buffa::json_helpers::ProtoJson(&self.price_fcfa), + )?; + } + { + if let ::core::option::Option::Some(__v) = self + .meetup_location + .as_option() + { + __map.serialize_entry("meetupLocation", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for BookPurchaseDetailsView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "BookPurchaseDetails"; + const FULL_NAME: &'static str = "bookbridge.v1.BookPurchaseDetails"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.BookPurchaseDetails"; + } + ::buffa::impl_default_view_instance!(BookPurchaseDetailsView); + ::buffa::impl_view_reborrow!(BookPurchaseDetailsView); + /** Self-contained, `'static` owned view of a `BookPurchaseDetails` message. + + Wraps [`::buffa::OwnedView`]`<`[`BookPurchaseDetailsView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`BookPurchaseDetailsView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct BookPurchaseDetailsOwnedView( + ::buffa::OwnedView>, + ); + impl BookPurchaseDetailsOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookPurchaseDetailsOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookPurchaseDetailsOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::BookPurchaseDetails, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + BookPurchaseDetailsOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`BookPurchaseDetailsView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &BookPurchaseDetailsView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::BookPurchaseDetails { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + /// Field 2: `title` + #[must_use] + pub fn title(&self) -> &'_ str { + self.0.reborrow().title + } + /// Field 3: `cover_url` + #[must_use] + pub fn cover_url(&self) -> &'_ str { + self.0.reborrow().cover_url + } + /// Field 4: `price_fcfa` + #[must_use] + pub fn price_fcfa(&self) -> i64 { + self.0.reborrow().price_fcfa + } + /// Field 5: `meetup_location` + #[must_use] + pub fn meetup_location( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::MeetupLocationView<'_>, + > { + &self.0.reborrow().meetup_location + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for BookPurchaseDetailsOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + BookPurchaseDetailsOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: BookPurchaseDetailsOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for BookPurchaseDetailsOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::BookPurchaseDetails { + type View<'a> = BookPurchaseDetailsView<'a>; + type ViewHandle = BookPurchaseDetailsOwnedView; + } + impl ::serde::Serialize for BookPurchaseDetailsOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateBookPurchaseRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + /// Field 2: `meetup_location_id` + pub meetup_location_id: ::core::option::Option<&'a str>, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateBookPurchaseRequestView<'a> { + type Owned = super::super::CreateBookPurchaseRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.meetup_location_id = Some( + ::buffa::types::borrow_str(&mut cur)?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateBookPurchaseRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateBookPurchaseRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateBookPurchaseRequest { + book_id: self.book_id.to_string(), + meetup_location_id: self.meetup_location_id.map(|s| s.to_string()), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateBookPurchaseRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + if let Some(ref v) = self.meetup_location_id { + size += 1u64 + ::buffa::types::string_encoded_len(v) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + if let Some(ref v) = self.meetup_location_id { + ::buffa::types::put_string_field(2u32, v, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateBookPurchaseRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + if let ::core::option::Option::Some(__v) = self.meetup_location_id { + __map.serialize_entry("meetupLocationId", __v)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateBookPurchaseRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBookPurchaseRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBookPurchaseRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookPurchaseRequest"; + } + ::buffa::impl_default_view_instance!(CreateBookPurchaseRequestView); + ::buffa::impl_view_reborrow!(CreateBookPurchaseRequestView); + /** Self-contained, `'static` owned view of a `CreateBookPurchaseRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateBookPurchaseRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateBookPurchaseRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateBookPurchaseRequestOwnedView( + ::buffa::OwnedView>, + ); + impl CreateBookPurchaseRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookPurchaseRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookPurchaseRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateBookPurchaseRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookPurchaseRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`CreateBookPurchaseRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateBookPurchaseRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateBookPurchaseRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + /// Field 2: `meetup_location_id` + #[must_use] + pub fn meetup_location_id(&self) -> ::core::option::Option<&'_ str> { + self.0.reborrow().meetup_location_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for CreateBookPurchaseRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateBookPurchaseRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateBookPurchaseRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for CreateBookPurchaseRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateBookPurchaseRequest { + type View<'a> = CreateBookPurchaseRequestView<'a>; + type ViewHandle = CreateBookPurchaseRequestOwnedView; + } + impl ::serde::Serialize for CreateBookPurchaseRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateBookPurchaseResponseView<'a> { + /// Field 1: `purchase` + pub purchase: ::buffa::MessageFieldView< + super::super::__buffa::view::PurchaseView<'a>, + >, + /// Fapshi session identifier to poll for confirmation. + /// + /// Field 2: `fapshi_transaction_id` + pub fapshi_transaction_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateBookPurchaseResponseView<'a> { + type Owned = super::super::CreateBookPurchaseResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.purchase.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.purchase = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.fapshi_transaction_id = ::buffa::types::borrow_str( + &mut cur, + )?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateBookPurchaseResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateBookPurchaseResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateBookPurchaseResponse { + purchase: match self.purchase.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Purchase, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + fapshi_transaction_id: self.fapshi_transaction_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateBookPurchaseResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.purchase.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.purchase.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.fapshi_transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len( + &self.fapshi_transaction_id, + ) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.purchase.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.purchase.write_to(__cache, buf); + } + if !self.fapshi_transaction_id.is_empty() { + ::buffa::types::put_string_field( + 2u32, + &self.fapshi_transaction_id, + buf, + ); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateBookPurchaseResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.purchase.as_option() + { + __map.serialize_entry("purchase", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str( + self.fapshi_transaction_id, + ) { + __map + .serialize_entry( + "fapshiTransactionId", + self.fapshi_transaction_id, + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateBookPurchaseResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateBookPurchaseResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateBookPurchaseResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateBookPurchaseResponse"; + } + ::buffa::impl_default_view_instance!(CreateBookPurchaseResponseView); + ::buffa::impl_view_reborrow!(CreateBookPurchaseResponseView); + /** Self-contained, `'static` owned view of a `CreateBookPurchaseResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateBookPurchaseResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateBookPurchaseResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateBookPurchaseResponseOwnedView( + ::buffa::OwnedView>, + ); + impl CreateBookPurchaseResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookPurchaseResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookPurchaseResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateBookPurchaseResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateBookPurchaseResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`CreateBookPurchaseResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateBookPurchaseResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateBookPurchaseResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `purchase` + #[must_use] + pub fn purchase( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::PurchaseView<'_>, + > { + &self.0.reborrow().purchase + } + /// Fapshi session identifier to poll for confirmation. + /// + /// Field 2: `fapshi_transaction_id` + #[must_use] + pub fn fapshi_transaction_id(&self) -> &'_ str { + self.0.reborrow().fapshi_transaction_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for CreateBookPurchaseResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateBookPurchaseResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateBookPurchaseResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for CreateBookPurchaseResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateBookPurchaseResponse { + type View<'a> = CreateBookPurchaseResponseView<'a>; + type ViewHandle = CreateBookPurchaseResponseOwnedView; + } + impl ::serde::Serialize for CreateBookPurchaseResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetPurchaseRequestView<'a> { + /// Field 1: `purchase_id` + pub purchase_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetPurchaseRequestView<'a> { + type Owned = super::super::GetPurchaseRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.purchase_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetPurchaseRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetPurchaseRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetPurchaseRequest { + purchase_id: self.purchase_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetPurchaseRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.purchase_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.purchase_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.purchase_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.purchase_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetPurchaseRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.purchase_id) { + __map.serialize_entry("purchaseId", self.purchase_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetPurchaseRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetPurchaseRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetPurchaseRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPurchaseRequest"; + } + ::buffa::impl_default_view_instance!(GetPurchaseRequestView); + ::buffa::impl_view_reborrow!(GetPurchaseRequestView); + /** Self-contained, `'static` owned view of a `GetPurchaseRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetPurchaseRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetPurchaseRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetPurchaseRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetPurchaseRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPurchaseRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPurchaseRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetPurchaseRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPurchaseRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetPurchaseRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetPurchaseRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetPurchaseRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `purchase_id` + #[must_use] + pub fn purchase_id(&self) -> &'_ str { + self.0.reborrow().purchase_id + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GetPurchaseRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + GetPurchaseRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetPurchaseRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GetPurchaseRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetPurchaseRequest { + type View<'a> = GetPurchaseRequestView<'a>; + type ViewHandle = GetPurchaseRequestOwnedView; + } + impl ::serde::Serialize for GetPurchaseRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetPurchaseResponseView<'a> { + /// Field 1: `purchase` + pub purchase: ::buffa::MessageFieldView< + super::super::__buffa::view::PurchaseView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetPurchaseResponseView<'a> { + type Owned = super::super::GetPurchaseResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.purchase.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.purchase = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetPurchaseResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetPurchaseResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetPurchaseResponse { + purchase: match self.purchase.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Purchase, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetPurchaseResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.purchase.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.purchase.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.purchase.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.purchase.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetPurchaseResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.purchase.as_option() + { + __map.serialize_entry("purchase", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetPurchaseResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetPurchaseResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetPurchaseResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPurchaseResponse"; + } + ::buffa::impl_default_view_instance!(GetPurchaseResponseView); + ::buffa::impl_view_reborrow!(GetPurchaseResponseView); + /** Self-contained, `'static` owned view of a `GetPurchaseResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetPurchaseResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetPurchaseResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetPurchaseResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetPurchaseResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPurchaseResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPurchaseResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetPurchaseResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPurchaseResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetPurchaseResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetPurchaseResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetPurchaseResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `purchase` + #[must_use] + pub fn purchase( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::PurchaseView<'_>, + > { + &self.0.reborrow().purchase + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GetPurchaseResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetPurchaseResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetPurchaseResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GetPurchaseResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetPurchaseResponse { + type View<'a> = GetPurchaseResponseView<'a>; + type ViewHandle = GetPurchaseResponseOwnedView; + } + impl ::serde::Serialize for GetPurchaseResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMyPurchasesRequestView<'a> { + /// Field 1: `page_token` + pub page_token: &'a str, + /// Field 2: `page_size` + pub page_size: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMyPurchasesRequestView<'a> { + type Owned = super::super::ListMyPurchasesRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMyPurchasesRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMyPurchasesRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMyPurchasesRequest { + page_token: self.page_token.to_string(), + page_size: self.page_size, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMyPurchasesRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMyPurchasesRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMyPurchasesRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMyPurchasesRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMyPurchasesRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyPurchasesRequest"; + } + ::buffa::impl_default_view_instance!(ListMyPurchasesRequestView); + ::buffa::impl_view_reborrow!(ListMyPurchasesRequestView); + /** Self-contained, `'static` owned view of a `ListMyPurchasesRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMyPurchasesRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMyPurchasesRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMyPurchasesRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListMyPurchasesRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyPurchasesRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyPurchasesRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMyPurchasesRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyPurchasesRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListMyPurchasesRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMyPurchasesRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMyPurchasesRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 2: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListMyPurchasesRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListMyPurchasesRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMyPurchasesRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListMyPurchasesRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMyPurchasesRequest { + type View<'a> = ListMyPurchasesRequestView<'a>; + type ViewHandle = ListMyPurchasesRequestOwnedView; + } + impl ::serde::Serialize for ListMyPurchasesRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMyPurchasesResponseView<'a> { + /// Field 1: `purchases` + pub purchases: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::PurchaseView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMyPurchasesResponseView<'a> { + type Owned = super::super::ListMyPurchasesResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::PurchaseView, + >(), + )?; + view.purchases + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMyPurchasesResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMyPurchasesResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMyPurchasesResponse { + purchases: self + .purchases + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMyPurchasesResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.purchases { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.purchases { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMyPurchasesResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.purchases.is_empty() { + __map.serialize_entry("purchases", &*self.purchases)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMyPurchasesResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMyPurchasesResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMyPurchasesResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMyPurchasesResponse"; + } + ::buffa::impl_default_view_instance!(ListMyPurchasesResponseView); + ::buffa::impl_view_reborrow!(ListMyPurchasesResponseView); + /** Self-contained, `'static` owned view of a `ListMyPurchasesResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMyPurchasesResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMyPurchasesResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMyPurchasesResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListMyPurchasesResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyPurchasesResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyPurchasesResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMyPurchasesResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMyPurchasesResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListMyPurchasesResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMyPurchasesResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMyPurchasesResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `purchases` + #[must_use] + pub fn purchases( + &self, + ) -> &::buffa::RepeatedView< + '_, + super::super::__buffa::view::PurchaseView<'_>, + > { + &self.0.reborrow().purchases + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListMyPurchasesResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListMyPurchasesResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMyPurchasesResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListMyPurchasesResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMyPurchasesResponse { + type View<'a> = ListMyPurchasesResponseView<'a>; + type ViewHandle = ListMyPurchasesResponseOwnedView; + } + impl ::serde::Serialize for ListMyPurchasesResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMySalesRequestView<'a> { + /// Field 1: `page_token` + pub page_token: &'a str, + /// Field 2: `page_size` + pub page_size: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMySalesRequestView<'a> { + type Owned = super::super::ListMySalesRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMySalesRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMySalesRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMySalesRequest { + page_token: self.page_token.to_string(), + page_size: self.page_size, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMySalesRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMySalesRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMySalesRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMySalesRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMySalesRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMySalesRequest"; + } + ::buffa::impl_default_view_instance!(ListMySalesRequestView); + ::buffa::impl_view_reborrow!(ListMySalesRequestView); + /** Self-contained, `'static` owned view of a `ListMySalesRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMySalesRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMySalesRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMySalesRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListMySalesRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMySalesRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMySalesRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMySalesRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMySalesRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListMySalesRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMySalesRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMySalesRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 2: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListMySalesRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + ListMySalesRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMySalesRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ListMySalesRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMySalesRequest { + type View<'a> = ListMySalesRequestView<'a>; + type ViewHandle = ListMySalesRequestOwnedView; + } + impl ::serde::Serialize for ListMySalesRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct SaleView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `transaction_id` + pub transaction_id: &'a str, + /// Field 3: `book` + pub book: ::buffa::MessageFieldView< + super::super::__buffa::view::BookPurchaseDetailsView<'a>, + >, + /// Field 4: `buyer_id` + pub buyer_id: &'a str, + /// Field 5: `status` + pub status: ::buffa::EnumValue, + /// Field 6: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for SaleView<'a> { + type Owned = super::super::Sale; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.transaction_id = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.book.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.book = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.buyer_id = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.status = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Sale { + id: self.id.to_string(), + transaction_id: self.transaction_id.to_string(), + book: match self.book.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::BookPurchaseDetails, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + buyer_id: self.buyer_id.to_string(), + status: self.status, + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for SaleView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.transaction_id) + as u64; + } + if self.book.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.book.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.buyer_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.buyer_id) as u64; + } + { + let val = self.status.to_i32(); + if val != 0 { + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; + } + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.transaction_id, buf); + } + if self.book.is_set() { + ::buffa::types::put_len_delimited_header( + 3u32, + u64::from(__cache.consume_next()), + buf, + ); + self.book.write_to(__cache, buf); + } + if !self.buyer_id.is_empty() { + ::buffa::types::put_string_field(4u32, &self.buyer_id, buf); + } + { + let val = self.status.to_i32(); + if val != 0 { + ::buffa::types::put_int32_field(5u32, val, buf); + } + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for SaleView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.transaction_id) { + __map.serialize_entry("transactionId", self.transaction_id)?; + } + { + if let ::core::option::Option::Some(__v) = self.book.as_option() { + __map.serialize_entry("book", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.buyer_id) { + __map.serialize_entry("buyerId", self.buyer_id)?; + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.status) { + __map.serialize_entry("status", &self.status)?; + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for SaleView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Sale"; + const FULL_NAME: &'static str = "bookbridge.v1.Sale"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Sale"; + } + ::buffa::impl_default_view_instance!(SaleView); + ::buffa::impl_view_reborrow!(SaleView); + /** Self-contained, `'static` owned view of a `Sale` message. + + Wraps [`::buffa::OwnedView`]`<`[`SaleView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`SaleView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct SaleOwnedView(::buffa::OwnedView>); + impl SaleOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SaleOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SaleOwnedView(::buffa::OwnedView::decode_with_options(bytes, opts)?), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Sale, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + SaleOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`SaleView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &SaleView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Sale { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `transaction_id` + #[must_use] + pub fn transaction_id(&self) -> &'_ str { + self.0.reborrow().transaction_id + } + /// Field 3: `book` + #[must_use] + pub fn book( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::BookPurchaseDetailsView<'_>, + > { + &self.0.reborrow().book + } + /// Field 4: `buyer_id` + #[must_use] + pub fn buyer_id(&self) -> &'_ str { + self.0.reborrow().buyer_id + } + /// Field 5: `status` + #[must_use] + pub fn status(&self) -> ::buffa::EnumValue { + self.0.reborrow().status + } + /// Field 6: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for SaleOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + SaleOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: SaleOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for SaleOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Sale { + type View<'a> = SaleView<'a>; + type ViewHandle = SaleOwnedView; + } + impl ::serde::Serialize for SaleOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListMySalesResponseView<'a> { + /// Field 1: `sales` + pub sales: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::SaleView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListMySalesResponseView<'a> { + type Owned = super::super::ListMySalesResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::SaleView, + >(), + )?; + view.sales + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListMySalesResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListMySalesResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListMySalesResponse { + sales: self + .sales + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListMySalesResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.sales { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.sales { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListMySalesResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.sales.is_empty() { + __map.serialize_entry("sales", &*self.sales)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListMySalesResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListMySalesResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListMySalesResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListMySalesResponse"; + } + ::buffa::impl_default_view_instance!(ListMySalesResponseView); + ::buffa::impl_view_reborrow!(ListMySalesResponseView); + /** Self-contained, `'static` owned view of a `ListMySalesResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListMySalesResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListMySalesResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListMySalesResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListMySalesResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMySalesResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMySalesResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListMySalesResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListMySalesResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListMySalesResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListMySalesResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListMySalesResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `sales` + #[must_use] + pub fn sales( + &self, + ) -> &::buffa::RepeatedView<'_, super::super::__buffa::view::SaleView<'_>> { + &self.0.reborrow().sales + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListMySalesResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListMySalesResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListMySalesResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ListMySalesResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListMySalesResponse { + type View<'a> = ListMySalesResponseView<'a>; + type ViewHandle = ListMySalesResponseOwnedView; + } + impl ::serde::Serialize for ListMySalesResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ConfirmReceiptRequestView<'a> { + /// Field 1: `purchase_id` + pub purchase_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ConfirmReceiptRequestView<'a> { + type Owned = super::super::ConfirmReceiptRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.purchase_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ConfirmReceiptRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ConfirmReceiptRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ConfirmReceiptRequest { + purchase_id: self.purchase_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ConfirmReceiptRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.purchase_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.purchase_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.purchase_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.purchase_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ConfirmReceiptRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.purchase_id) { + __map.serialize_entry("purchaseId", self.purchase_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ConfirmReceiptRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ConfirmReceiptRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ConfirmReceiptRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ConfirmReceiptRequest"; + } + ::buffa::impl_default_view_instance!(ConfirmReceiptRequestView); + ::buffa::impl_view_reborrow!(ConfirmReceiptRequestView); + /** Self-contained, `'static` owned view of a `ConfirmReceiptRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ConfirmReceiptRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ConfirmReceiptRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ConfirmReceiptRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ConfirmReceiptRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConfirmReceiptRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConfirmReceiptRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ConfirmReceiptRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConfirmReceiptRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ConfirmReceiptRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ConfirmReceiptRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ConfirmReceiptRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `purchase_id` + #[must_use] + pub fn purchase_id(&self) -> &'_ str { + self.0.reborrow().purchase_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ConfirmReceiptRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ConfirmReceiptRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ConfirmReceiptRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ConfirmReceiptRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ConfirmReceiptRequest { + type View<'a> = ConfirmReceiptRequestView<'a>; + type ViewHandle = ConfirmReceiptRequestOwnedView; + } + impl ::serde::Serialize for ConfirmReceiptRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ConfirmReceiptResponseView<'a> { + /// Field 1: `purchase` + pub purchase: ::buffa::MessageFieldView< + super::super::__buffa::view::PurchaseView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ConfirmReceiptResponseView<'a> { + type Owned = super::super::ConfirmReceiptResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.purchase.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.purchase = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ConfirmReceiptResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ConfirmReceiptResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ConfirmReceiptResponse { + purchase: match self.purchase.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Purchase, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ConfirmReceiptResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.purchase.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.purchase.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.purchase.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.purchase.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ConfirmReceiptResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.purchase.as_option() + { + __map.serialize_entry("purchase", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ConfirmReceiptResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ConfirmReceiptResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ConfirmReceiptResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ConfirmReceiptResponse"; + } + ::buffa::impl_default_view_instance!(ConfirmReceiptResponseView); + ::buffa::impl_view_reborrow!(ConfirmReceiptResponseView); + /** Self-contained, `'static` owned view of a `ConfirmReceiptResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ConfirmReceiptResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ConfirmReceiptResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ConfirmReceiptResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ConfirmReceiptResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConfirmReceiptResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConfirmReceiptResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ConfirmReceiptResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ConfirmReceiptResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ConfirmReceiptResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ConfirmReceiptResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ConfirmReceiptResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `purchase` + #[must_use] + pub fn purchase( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::PurchaseView<'_>, + > { + &self.0.reborrow().purchase + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ConfirmReceiptResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ConfirmReceiptResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ConfirmReceiptResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ConfirmReceiptResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ConfirmReceiptResponse { + type View<'a> = ConfirmReceiptResponseView<'a>; + type ViewHandle = ConfirmReceiptResponseOwnedView; + } + impl ::serde::Serialize for ConfirmReceiptResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct DisputePurchaseRequestView<'a> { + /// Field 1: `purchase_id` + pub purchase_id: &'a str, + /// Field 2: `reason` + pub reason: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for DisputePurchaseRequestView<'a> { + type Owned = super::super::DisputePurchaseRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.purchase_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.reason = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::DisputePurchaseRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::DisputePurchaseRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::DisputePurchaseRequest { + purchase_id: self.purchase_id.to_string(), + reason: self.reason.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for DisputePurchaseRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.purchase_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.purchase_id) + as u64; + } + if !self.reason.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.reason) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.purchase_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.purchase_id, buf); + } + if !self.reason.is_empty() { + ::buffa::types::put_string_field(2u32, &self.reason, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for DisputePurchaseRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.purchase_id) { + __map.serialize_entry("purchaseId", self.purchase_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.reason) { + __map.serialize_entry("reason", self.reason)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for DisputePurchaseRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DisputePurchaseRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.DisputePurchaseRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DisputePurchaseRequest"; + } + ::buffa::impl_default_view_instance!(DisputePurchaseRequestView); + ::buffa::impl_view_reborrow!(DisputePurchaseRequestView); + /** Self-contained, `'static` owned view of a `DisputePurchaseRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`DisputePurchaseRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`DisputePurchaseRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct DisputePurchaseRequestOwnedView( + ::buffa::OwnedView>, + ); + impl DisputePurchaseRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DisputePurchaseRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DisputePurchaseRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::DisputePurchaseRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DisputePurchaseRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`DisputePurchaseRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &DisputePurchaseRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::DisputePurchaseRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `purchase_id` + #[must_use] + pub fn purchase_id(&self) -> &'_ str { + self.0.reborrow().purchase_id + } + /// Field 2: `reason` + #[must_use] + pub fn reason(&self) -> &'_ str { + self.0.reborrow().reason + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for DisputePurchaseRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + DisputePurchaseRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: DisputePurchaseRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for DisputePurchaseRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::DisputePurchaseRequest { + type View<'a> = DisputePurchaseRequestView<'a>; + type ViewHandle = DisputePurchaseRequestOwnedView; + } + impl ::serde::Serialize for DisputePurchaseRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct DisputePurchaseResponseView<'a> { + /// Field 1: `purchase` + pub purchase: ::buffa::MessageFieldView< + super::super::__buffa::view::PurchaseView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for DisputePurchaseResponseView<'a> { + type Owned = super::super::DisputePurchaseResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.purchase.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.purchase = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::DisputePurchaseResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::DisputePurchaseResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::DisputePurchaseResponse { + purchase: match self.purchase.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Purchase, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for DisputePurchaseResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.purchase.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.purchase.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.purchase.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.purchase.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for DisputePurchaseResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.purchase.as_option() + { + __map.serialize_entry("purchase", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for DisputePurchaseResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DisputePurchaseResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.DisputePurchaseResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DisputePurchaseResponse"; + } + ::buffa::impl_default_view_instance!(DisputePurchaseResponseView); + ::buffa::impl_view_reborrow!(DisputePurchaseResponseView); + /** Self-contained, `'static` owned view of a `DisputePurchaseResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`DisputePurchaseResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`DisputePurchaseResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct DisputePurchaseResponseOwnedView( + ::buffa::OwnedView>, + ); + impl DisputePurchaseResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DisputePurchaseResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DisputePurchaseResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::DisputePurchaseResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DisputePurchaseResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`DisputePurchaseResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &DisputePurchaseResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::DisputePurchaseResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `purchase` + #[must_use] + pub fn purchase( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::PurchaseView<'_>, + > { + &self.0.reborrow().purchase + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for DisputePurchaseResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + DisputePurchaseResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: DisputePurchaseResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for DisputePurchaseResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::DisputePurchaseResponse { + type View<'a> = DisputePurchaseResponseView<'a>; + type ViewHandle = DisputePurchaseResponseOwnedView; + } + impl ::serde::Serialize for DisputePurchaseResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to the reviews table. + #[derive(Clone, Debug, Default)] + pub struct ReviewView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `author` + pub author: ::buffa::MessageFieldView< + super::super::__buffa::view::UserSummaryView<'a>, + >, + /// Field 3: `reviewee_id` + pub reviewee_id: &'a str, + /// Field 4: `rating` + pub rating: i32, + /// Field 5: `content` + pub content: &'a str, + /// Field 6: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ReviewView<'a> { + type Owned = super::super::Review; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.author.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.author = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.reviewee_id = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.rating = ::buffa::types::decode_int32(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.content = ::buffa::types::borrow_str(&mut cur)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Review { + id: self.id.to_string(), + author: match self.author.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::UserSummary, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + reviewee_id: self.reviewee_id.to_string(), + rating: self.rating, + content: self.content.to_string(), + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ReviewView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if self.author.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.author.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.reviewee_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.reviewee_id) + as u64; + } + if self.rating != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.rating) as u64; + } + if !self.content.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.content) as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if self.author.is_set() { + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); + self.author.write_to(__cache, buf); + } + if !self.reviewee_id.is_empty() { + ::buffa::types::put_string_field(3u32, &self.reviewee_id, buf); + } + if self.rating != 0i32 { + ::buffa::types::put_int32_field(4u32, self.rating, buf); + } + if !self.content.is_empty() { + ::buffa::types::put_string_field(5u32, &self.content, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 6u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ReviewView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + { + if let ::core::option::Option::Some(__v) = self.author.as_option() { + __map.serialize_entry("author", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.reviewee_id) { + __map.serialize_entry("revieweeId", self.reviewee_id)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.rating) { + __map + .serialize_entry( + "rating", + &::buffa::json_helpers::ProtoJson(&self.rating), + )?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.content) { + __map.serialize_entry("content", self.content)?; + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ReviewView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Review"; + const FULL_NAME: &'static str = "bookbridge.v1.Review"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Review"; + } + ::buffa::impl_default_view_instance!(ReviewView); + ::buffa::impl_view_reborrow!(ReviewView); + /** Self-contained, `'static` owned view of a `Review` message. + + Wraps [`::buffa::OwnedView`]`<`[`ReviewView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ReviewView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ReviewOwnedView(::buffa::OwnedView>); + impl ReviewOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ReviewOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ReviewOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Review, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ReviewOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ReviewView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ReviewView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Review { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `author` + #[must_use] + pub fn author( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::UserSummaryView<'_>, + > { + &self.0.reborrow().author + } + /// Field 3: `reviewee_id` + #[must_use] + pub fn reviewee_id(&self) -> &'_ str { + self.0.reborrow().reviewee_id + } + /// Field 4: `rating` + #[must_use] + pub fn rating(&self) -> i32 { + self.0.reborrow().rating + } + /// Field 5: `content` + #[must_use] + pub fn content(&self) -> &'_ str { + self.0.reborrow().content + } + /// Field 6: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ReviewOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + ReviewOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ReviewOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ReviewOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Review { + type View<'a> = ReviewView<'a>; + type ViewHandle = ReviewOwnedView; + } + impl ::serde::Serialize for ReviewOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateReviewRequestView<'a> { + /// Field 1: `reviewee_id` + pub reviewee_id: &'a str, + /// Field 2: `transaction_id` + pub transaction_id: &'a str, + /// Field 3: `rating` + pub rating: i32, + /// Field 4: `content` + pub content: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateReviewRequestView<'a> { + type Owned = super::super::CreateReviewRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.reviewee_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.transaction_id = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.rating = ::buffa::types::decode_int32(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.content = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateReviewRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateReviewRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateReviewRequest { + reviewee_id: self.reviewee_id.to_string(), + transaction_id: self.transaction_id.to_string(), + rating: self.rating, + content: self.content.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateReviewRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.reviewee_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.reviewee_id) + as u64; + } + if !self.transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.transaction_id) + as u64; + } + if self.rating != 0i32 { + size += 1u64 + ::buffa::types::int32_encoded_len(self.rating) as u64; + } + if !self.content.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.content) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.reviewee_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.reviewee_id, buf); + } + if !self.transaction_id.is_empty() { + ::buffa::types::put_string_field(2u32, &self.transaction_id, buf); + } + if self.rating != 0i32 { + ::buffa::types::put_int32_field(3u32, self.rating, buf); + } + if !self.content.is_empty() { + ::buffa::types::put_string_field(4u32, &self.content, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateReviewRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.reviewee_id) { + __map.serialize_entry("revieweeId", self.reviewee_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.transaction_id) { + __map.serialize_entry("transactionId", self.transaction_id)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.rating) { + __map + .serialize_entry( + "rating", + &::buffa::json_helpers::ProtoJson(&self.rating), + )?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.content) { + __map.serialize_entry("content", self.content)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateReviewRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateReviewRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateReviewRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateReviewRequest"; + } + ::buffa::impl_default_view_instance!(CreateReviewRequestView); + ::buffa::impl_view_reborrow!(CreateReviewRequestView); + /** Self-contained, `'static` owned view of a `CreateReviewRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateReviewRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateReviewRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateReviewRequestOwnedView( + ::buffa::OwnedView>, + ); + impl CreateReviewRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateReviewRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateReviewRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateReviewRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateReviewRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateReviewRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateReviewRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateReviewRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `reviewee_id` + #[must_use] + pub fn reviewee_id(&self) -> &'_ str { + self.0.reborrow().reviewee_id + } + /// Field 2: `transaction_id` + #[must_use] + pub fn transaction_id(&self) -> &'_ str { + self.0.reborrow().transaction_id + } + /// Field 3: `rating` + #[must_use] + pub fn rating(&self) -> i32 { + self.0.reborrow().rating + } + /// Field 4: `content` + #[must_use] + pub fn content(&self) -> &'_ str { + self.0.reborrow().content + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for CreateReviewRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateReviewRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateReviewRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for CreateReviewRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateReviewRequest { + type View<'a> = CreateReviewRequestView<'a>; + type ViewHandle = CreateReviewRequestOwnedView; + } + impl ::serde::Serialize for CreateReviewRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateReviewResponseView<'a> { + /// Field 1: `review` + pub review: ::buffa::MessageFieldView< + super::super::__buffa::view::ReviewView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateReviewResponseView<'a> { + type Owned = super::super::CreateReviewResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.review.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.review = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateReviewResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateReviewResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateReviewResponse { + review: match self.review.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Review, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateReviewResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.review.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.review.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.review.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.review.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateReviewResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.review.as_option() { + __map.serialize_entry("review", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateReviewResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateReviewResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateReviewResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateReviewResponse"; + } + ::buffa::impl_default_view_instance!(CreateReviewResponseView); + ::buffa::impl_view_reborrow!(CreateReviewResponseView); + /** Self-contained, `'static` owned view of a `CreateReviewResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateReviewResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateReviewResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateReviewResponseOwnedView( + ::buffa::OwnedView>, + ); + impl CreateReviewResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateReviewResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateReviewResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateReviewResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateReviewResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateReviewResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateReviewResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateReviewResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `review` + #[must_use] + pub fn review( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::ReviewView<'_>, + > { + &self.0.reborrow().review + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for CreateReviewResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateReviewResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateReviewResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for CreateReviewResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateReviewResponse { + type View<'a> = CreateReviewResponseView<'a>; + type ViewHandle = CreateReviewResponseOwnedView; + } + impl ::serde::Serialize for CreateReviewResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListUserReviewsRequestView<'a> { + /// Field 1: `user_id` + pub user_id: &'a str, + /// Field 2: `page_token` + pub page_token: &'a str, + /// Field 3: `page_size` + pub page_size: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListUserReviewsRequestView<'a> { + type Owned = super::super::ListUserReviewsRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.user_id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListUserReviewsRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListUserReviewsRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListUserReviewsRequest { + user_id: self.user_id.to_string(), + page_token: self.page_token.to_string(), + page_size: self.page_size, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListUserReviewsRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.user_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.user_id) as u64; + } + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.user_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.user_id, buf); + } + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(3u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListUserReviewsRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.user_id) { + __map.serialize_entry("userId", self.user_id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListUserReviewsRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListUserReviewsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListUserReviewsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListUserReviewsRequest"; + } + ::buffa::impl_default_view_instance!(ListUserReviewsRequestView); + ::buffa::impl_view_reborrow!(ListUserReviewsRequestView); + /** Self-contained, `'static` owned view of a `ListUserReviewsRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListUserReviewsRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListUserReviewsRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListUserReviewsRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListUserReviewsRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListUserReviewsRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListUserReviewsRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListUserReviewsRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListUserReviewsRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListUserReviewsRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListUserReviewsRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListUserReviewsRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `user_id` + #[must_use] + pub fn user_id(&self) -> &'_ str { + self.0.reborrow().user_id + } + /// Field 2: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 3: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListUserReviewsRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListUserReviewsRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListUserReviewsRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListUserReviewsRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListUserReviewsRequest { + type View<'a> = ListUserReviewsRequestView<'a>; + type ViewHandle = ListUserReviewsRequestOwnedView; + } + impl ::serde::Serialize for ListUserReviewsRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListUserReviewsResponseView<'a> { + /// Field 1: `reviews` + pub reviews: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::ReviewView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListUserReviewsResponseView<'a> { + type Owned = super::super::ListUserReviewsResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::ReviewView, + >(), + )?; + view.reviews + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListUserReviewsResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListUserReviewsResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListUserReviewsResponse { + reviews: self + .reviews + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListUserReviewsResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.reviews { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.reviews { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListUserReviewsResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.reviews.is_empty() { + __map.serialize_entry("reviews", &*self.reviews)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListUserReviewsResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListUserReviewsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListUserReviewsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListUserReviewsResponse"; + } + ::buffa::impl_default_view_instance!(ListUserReviewsResponseView); + ::buffa::impl_view_reborrow!(ListUserReviewsResponseView); + /** Self-contained, `'static` owned view of a `ListUserReviewsResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListUserReviewsResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListUserReviewsResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListUserReviewsResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListUserReviewsResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListUserReviewsResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListUserReviewsResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListUserReviewsResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListUserReviewsResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`ListUserReviewsResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListUserReviewsResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListUserReviewsResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `reviews` + #[must_use] + pub fn reviews( + &self, + ) -> &::buffa::RepeatedView< + '_, + super::super::__buffa::view::ReviewView<'_>, + > { + &self.0.reborrow().reviews + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for ListUserReviewsResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListUserReviewsResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListUserReviewsResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListUserReviewsResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListUserReviewsResponse { + type View<'a> = ListUserReviewsResponseView<'a>; + type ViewHandle = ListUserReviewsResponseOwnedView; + } + impl ::serde::Serialize for ListUserReviewsResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct HasReviewedTransactionRequestView<'a> { + /// Field 1: `transaction_id` + pub transaction_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for HasReviewedTransactionRequestView<'a> { + type Owned = super::super::HasReviewedTransactionRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.transaction_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::HasReviewedTransactionRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::HasReviewedTransactionRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::HasReviewedTransactionRequest { + transaction_id: self.transaction_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for HasReviewedTransactionRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.transaction_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.transaction_id) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.transaction_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.transaction_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for HasReviewedTransactionRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.transaction_id) { + __map.serialize_entry("transactionId", self.transaction_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for HasReviewedTransactionRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "HasReviewedTransactionRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.HasReviewedTransactionRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.HasReviewedTransactionRequest"; + } + ::buffa::impl_default_view_instance!(HasReviewedTransactionRequestView); + ::buffa::impl_view_reborrow!(HasReviewedTransactionRequestView); + /** Self-contained, `'static` owned view of a `HasReviewedTransactionRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`HasReviewedTransactionRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`HasReviewedTransactionRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct HasReviewedTransactionRequestOwnedView( + ::buffa::OwnedView>, + ); + impl HasReviewedTransactionRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + HasReviewedTransactionRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + HasReviewedTransactionRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::HasReviewedTransactionRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + HasReviewedTransactionRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`HasReviewedTransactionRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &HasReviewedTransactionRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::HasReviewedTransactionRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `transaction_id` + #[must_use] + pub fn transaction_id(&self) -> &'_ str { + self.0.reborrow().transaction_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for HasReviewedTransactionRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + HasReviewedTransactionRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: HasReviewedTransactionRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for HasReviewedTransactionRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::HasReviewedTransactionRequest { + type View<'a> = HasReviewedTransactionRequestView<'a>; + type ViewHandle = HasReviewedTransactionRequestOwnedView; + } + impl ::serde::Serialize for HasReviewedTransactionRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct HasReviewedTransactionResponseView<'a> { + /// Field 1: `has_reviewed` + pub has_reviewed: bool, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for HasReviewedTransactionResponseView<'a> { + type Owned = super::super::HasReviewedTransactionResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.has_reviewed = ::buffa::types::decode_bool(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::HasReviewedTransactionResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::HasReviewedTransactionResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::HasReviewedTransactionResponse { + has_reviewed: self.has_reviewed, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for HasReviewedTransactionResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.has_reviewed { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.has_reviewed { + ::buffa::types::put_bool_field(1u32, self.has_reviewed, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for HasReviewedTransactionResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if self.has_reviewed { + __map.serialize_entry("hasReviewed", &self.has_reviewed)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for HasReviewedTransactionResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "HasReviewedTransactionResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.HasReviewedTransactionResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.HasReviewedTransactionResponse"; + } + ::buffa::impl_default_view_instance!(HasReviewedTransactionResponseView); + ::buffa::impl_view_reborrow!(HasReviewedTransactionResponseView); + /** Self-contained, `'static` owned view of a `HasReviewedTransactionResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`HasReviewedTransactionResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`HasReviewedTransactionResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct HasReviewedTransactionResponseOwnedView( + ::buffa::OwnedView>, + ); + impl HasReviewedTransactionResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + HasReviewedTransactionResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + HasReviewedTransactionResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::HasReviewedTransactionResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + HasReviewedTransactionResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`HasReviewedTransactionResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &HasReviewedTransactionResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::HasReviewedTransactionResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `has_reviewed` + #[must_use] + pub fn has_reviewed(&self) -> bool { + self.0.reborrow().has_reviewed + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for HasReviewedTransactionResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + HasReviewedTransactionResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: HasReviewedTransactionResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for HasReviewedTransactionResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::HasReviewedTransactionResponse { + type View<'a> = HasReviewedTransactionResponseView<'a>; + type ViewHandle = HasReviewedTransactionResponseOwnedView; + } + impl ::serde::Serialize for HasReviewedTransactionResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Aggregate platform statistics for the impact screen. + #[derive(Clone, Debug, Default)] + pub struct PlatformStatsView<'a> { + /// Field 1: `total_books_circulated` + pub total_books_circulated: i64, + /// Field 2: `total_students_reached` + pub total_students_reached: i64, + /// Field 3: `total_money_saved_fcfa` + pub total_money_saved_fcfa: i64, + /// Field 4: `total_co2_avoided_kg` + pub total_co2_avoided_kg: f64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for PlatformStatsView<'a> { + type Owned = super::super::PlatformStats; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.total_books_circulated = ::buffa::types::decode_int64( + &mut cur, + )?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.total_students_reached = ::buffa::types::decode_int64( + &mut cur, + )?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.total_money_saved_fcfa = ::buffa::types::decode_int64( + &mut cur, + )?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Fixed64, + )?; + view.total_co2_avoided_kg = ::buffa::types::decode_double( + &mut cur, + )?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::PlatformStats, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::PlatformStats, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::PlatformStats { + total_books_circulated: self.total_books_circulated, + total_students_reached: self.total_students_reached, + total_money_saved_fcfa: self.total_money_saved_fcfa, + total_co2_avoided_kg: self.total_co2_avoided_kg, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for PlatformStatsView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.total_books_circulated != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len( + self.total_books_circulated, + ) as u64; + } + if self.total_students_reached != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len( + self.total_students_reached, + ) as u64; + } + if self.total_money_saved_fcfa != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len( + self.total_money_saved_fcfa, + ) as u64; + } + if self.total_co2_avoided_kg.to_bits() != 0u64 { + size += 1u64 + ::buffa::types::FIXED64_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.total_books_circulated != 0i64 { + ::buffa::types::put_int64_field( + 1u32, + self.total_books_circulated, + buf, + ); + } + if self.total_students_reached != 0i64 { + ::buffa::types::put_int64_field( + 2u32, + self.total_students_reached, + buf, + ); + } + if self.total_money_saved_fcfa != 0i64 { + ::buffa::types::put_int64_field( + 3u32, + self.total_money_saved_fcfa, + buf, + ); + } + if self.total_co2_avoided_kg.to_bits() != 0u64 { + ::buffa::types::put_double_field( + 4u32, + self.total_co2_avoided_kg, + buf, + ); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for PlatformStatsView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_zero_i64( + &self.total_books_circulated, + ) { + __map + .serialize_entry( + "totalBooksCirculated", + &::buffa::json_helpers::ProtoJson( + &self.total_books_circulated, + ), + )?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64( + &self.total_students_reached, + ) { + __map + .serialize_entry( + "totalStudentsReached", + &::buffa::json_helpers::ProtoJson( + &self.total_students_reached, + ), + )?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64( + &self.total_money_saved_fcfa, + ) { + __map + .serialize_entry( + "totalMoneySavedFcfa", + &::buffa::json_helpers::ProtoJson( + &self.total_money_saved_fcfa, + ), + )?; + } + if !::buffa::json_helpers::skip_if::is_zero_f64( + &self.total_co2_avoided_kg, + ) { + __map + .serialize_entry( + "totalCo2AvoidedKg", + &::buffa::json_helpers::ProtoJson(&self.total_co2_avoided_kg), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for PlatformStatsView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "PlatformStats"; + const FULL_NAME: &'static str = "bookbridge.v1.PlatformStats"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.PlatformStats"; + } + ::buffa::impl_default_view_instance!(PlatformStatsView); + ::buffa::impl_view_reborrow!(PlatformStatsView); + /** Self-contained, `'static` owned view of a `PlatformStats` message. + + Wraps [`::buffa::OwnedView`]`<`[`PlatformStatsView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`PlatformStatsView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct PlatformStatsOwnedView( + ::buffa::OwnedView>, + ); + impl PlatformStatsOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PlatformStatsOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PlatformStatsOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::PlatformStats, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + PlatformStatsOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`PlatformStatsView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &PlatformStatsView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::PlatformStats { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `total_books_circulated` + #[must_use] + pub fn total_books_circulated(&self) -> i64 { + self.0.reborrow().total_books_circulated + } + /// Field 2: `total_students_reached` + #[must_use] + pub fn total_students_reached(&self) -> i64 { + self.0.reborrow().total_students_reached + } + /// Field 3: `total_money_saved_fcfa` + #[must_use] + pub fn total_money_saved_fcfa(&self) -> i64 { + self.0.reborrow().total_money_saved_fcfa + } + /// Field 4: `total_co2_avoided_kg` + #[must_use] + pub fn total_co2_avoided_kg(&self) -> f64 { + self.0.reborrow().total_co2_avoided_kg + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for PlatformStatsOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + PlatformStatsOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: PlatformStatsOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for PlatformStatsOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::PlatformStats { + type View<'a> = PlatformStatsView<'a>; + type ViewHandle = PlatformStatsOwnedView; + } + impl ::serde::Serialize for PlatformStatsOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetPlatformStatsRequestView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetPlatformStatsRequestView<'a> { + type Owned = super::super::GetPlatformStatsRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetPlatformStatsRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetPlatformStatsRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetPlatformStatsRequest { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetPlatformStatsRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetPlatformStatsRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetPlatformStatsRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetPlatformStatsRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetPlatformStatsRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPlatformStatsRequest"; + } + ::buffa::impl_default_view_instance!(GetPlatformStatsRequestView); + ::buffa::impl_view_reborrow!(GetPlatformStatsRequestView); + /** Self-contained, `'static` owned view of a `GetPlatformStatsRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetPlatformStatsRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetPlatformStatsRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetPlatformStatsRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetPlatformStatsRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPlatformStatsRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPlatformStatsRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetPlatformStatsRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPlatformStatsRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`GetPlatformStatsRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetPlatformStatsRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetPlatformStatsRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetPlatformStatsRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetPlatformStatsRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetPlatformStatsRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetPlatformStatsRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetPlatformStatsRequest { + type View<'a> = GetPlatformStatsRequestView<'a>; + type ViewHandle = GetPlatformStatsRequestOwnedView; + } + impl ::serde::Serialize for GetPlatformStatsRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetPlatformStatsResponseView<'a> { + /// Field 1: `stats` + pub stats: ::buffa::MessageFieldView< + super::super::__buffa::view::PlatformStatsView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetPlatformStatsResponseView<'a> { + type Owned = super::super::GetPlatformStatsResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.stats.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.stats = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetPlatformStatsResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetPlatformStatsResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetPlatformStatsResponse { + stats: match self.stats.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::PlatformStats, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetPlatformStatsResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.stats.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.stats.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.stats.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.stats.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetPlatformStatsResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.stats.as_option() { + __map.serialize_entry("stats", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetPlatformStatsResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetPlatformStatsResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetPlatformStatsResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetPlatformStatsResponse"; + } + ::buffa::impl_default_view_instance!(GetPlatformStatsResponseView); + ::buffa::impl_view_reborrow!(GetPlatformStatsResponseView); + /** Self-contained, `'static` owned view of a `GetPlatformStatsResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetPlatformStatsResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetPlatformStatsResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetPlatformStatsResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetPlatformStatsResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPlatformStatsResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPlatformStatsResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetPlatformStatsResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetPlatformStatsResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`GetPlatformStatsResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetPlatformStatsResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetPlatformStatsResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `stats` + #[must_use] + pub fn stats( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::PlatformStatsView<'_>, + > { + &self.0.reborrow().stats + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for GetPlatformStatsResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + GetPlatformStatsResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetPlatformStatsResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for GetPlatformStatsResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetPlatformStatsResponse { + type View<'a> = GetPlatformStatsResponseView<'a>; + type ViewHandle = GetPlatformStatsResponseOwnedView; + } + impl ::serde::Serialize for GetPlatformStatsResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + /// Maps to the uploads table. + #[derive(Clone, Debug, Default)] + pub struct UploadView<'a> { + /// Field 1: `id` + pub id: &'a str, + /// Field 2: `storage_key` + pub storage_key: &'a str, + /// Field 3: `file_name` + pub file_name: &'a str, + /// Field 4: `content_type` + pub content_type: &'a str, + /// Field 5: `size_bytes` + pub size_bytes: i64, + /// Field 6: `url` + pub url: &'a str, + /// Field 7: `created_at` + pub created_at: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for UploadView<'a> { + type Owned = super::super::Upload; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.id = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.storage_key = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.file_name = ::buffa::types::borrow_str(&mut cur)?; + } + 4u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.content_type = ::buffa::types::borrow_str(&mut cur)?; + } + 5u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.size_bytes = ::buffa::types::decode_int64(&mut cur)?; + } + 6u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.url = ::buffa::types::borrow_str(&mut cur)?; + } + 7u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.created_at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.created_at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::Upload { + id: self.id.to_string(), + storage_key: self.storage_key.to_string(), + file_name: self.file_name.to_string(), + content_type: self.content_type.to_string(), + size_bytes: self.size_bytes, + url: self.url.to_string(), + created_at: match self.created_at.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for UploadView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.id.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.id) as u64; + } + if !self.storage_key.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.storage_key) + as u64; + } + if !self.file_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.file_name) as u64; + } + if !self.content_type.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.content_type) + as u64; + } + if self.size_bytes != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.size_bytes) as u64; + } + if !self.url.is_empty() { + size += 1u64 + ::buffa::types::string_encoded_len(&self.url) as u64; + } + if self.created_at.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.created_at.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.id, buf); + } + if !self.storage_key.is_empty() { + ::buffa::types::put_string_field(2u32, &self.storage_key, buf); + } + if !self.file_name.is_empty() { + ::buffa::types::put_string_field(3u32, &self.file_name, buf); + } + if !self.content_type.is_empty() { + ::buffa::types::put_string_field(4u32, &self.content_type, buf); + } + if self.size_bytes != 0i64 { + ::buffa::types::put_int64_field(5u32, self.size_bytes, buf); + } + if !self.url.is_empty() { + ::buffa::types::put_string_field(6u32, &self.url, buf); + } + if self.created_at.is_set() { + ::buffa::types::put_len_delimited_header( + 7u32, + u64::from(__cache.consume_next()), + buf, + ); + self.created_at.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for UploadView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.id) { + __map.serialize_entry("id", self.id)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.storage_key) { + __map.serialize_entry("storageKey", self.storage_key)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.file_name) { + __map.serialize_entry("fileName", self.file_name)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.content_type) { + __map.serialize_entry("contentType", self.content_type)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.size_bytes) { + __map + .serialize_entry( + "sizeBytes", + &::buffa::json_helpers::ProtoJson(&self.size_bytes), + )?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.url) { + __map.serialize_entry("url", self.url)?; + } + { + if let ::core::option::Option::Some(__v) = self + .created_at + .as_option() + { + __map.serialize_entry("createdAt", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for UploadView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "Upload"; + const FULL_NAME: &'static str = "bookbridge.v1.Upload"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.Upload"; + } + ::buffa::impl_default_view_instance!(UploadView); + ::buffa::impl_view_reborrow!(UploadView); + /** Self-contained, `'static` owned view of a `Upload` message. + + Wraps [`::buffa::OwnedView`]`<`[`UploadView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`UploadView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct UploadOwnedView(::buffa::OwnedView>); + impl UploadOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UploadOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UploadOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Upload, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + UploadOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`UploadView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &UploadView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Upload { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `id` + #[must_use] + pub fn id(&self) -> &'_ str { + self.0.reborrow().id + } + /// Field 2: `storage_key` + #[must_use] + pub fn storage_key(&self) -> &'_ str { + self.0.reborrow().storage_key + } + /// Field 3: `file_name` + #[must_use] + pub fn file_name(&self) -> &'_ str { + self.0.reborrow().file_name + } + /// Field 4: `content_type` + #[must_use] + pub fn content_type(&self) -> &'_ str { + self.0.reborrow().content_type + } + /// Field 5: `size_bytes` + #[must_use] + pub fn size_bytes(&self) -> i64 { + self.0.reborrow().size_bytes + } + /// Field 6: `url` + #[must_use] + pub fn url(&self) -> &'_ str { + self.0.reborrow().url + } + /// Field 7: `created_at` + #[must_use] + pub fn created_at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().created_at + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for UploadOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + UploadOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: UploadOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for UploadOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Upload { + type View<'a> = UploadView<'a>; + type ViewHandle = UploadOwnedView; + } + impl ::serde::Serialize for UploadOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateUploadRequestView<'a> { + /// Field 1: `file_name` + pub file_name: &'a str, + /// Field 2: `content_type` + pub content_type: &'a str, + /// Field 3: `size_bytes` + pub size_bytes: i64, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateUploadRequestView<'a> { + type Owned = super::super::CreateUploadRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.file_name = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.content_type = ::buffa::types::borrow_str(&mut cur)?; + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.size_bytes = ::buffa::types::decode_int64(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateUploadRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateUploadRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateUploadRequest { + file_name: self.file_name.to_string(), + content_type: self.content_type.to_string(), + size_bytes: self.size_bytes, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateUploadRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.file_name.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.file_name) as u64; + } + if !self.content_type.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.content_type) + as u64; + } + if self.size_bytes != 0i64 { + size + += 1u64 + + ::buffa::types::int64_encoded_len(self.size_bytes) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.file_name.is_empty() { + ::buffa::types::put_string_field(1u32, &self.file_name, buf); + } + if !self.content_type.is_empty() { + ::buffa::types::put_string_field(2u32, &self.content_type, buf); + } + if self.size_bytes != 0i64 { + ::buffa::types::put_int64_field(3u32, self.size_bytes, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateUploadRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.file_name) { + __map.serialize_entry("fileName", self.file_name)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.content_type) { + __map.serialize_entry("contentType", self.content_type)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i64(&self.size_bytes) { + __map + .serialize_entry( + "sizeBytes", + &::buffa::json_helpers::ProtoJson(&self.size_bytes), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateUploadRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateUploadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateUploadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateUploadRequest"; + } + ::buffa::impl_default_view_instance!(CreateUploadRequestView); + ::buffa::impl_view_reborrow!(CreateUploadRequestView); + /** Self-contained, `'static` owned view of a `CreateUploadRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateUploadRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateUploadRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateUploadRequestOwnedView( + ::buffa::OwnedView>, + ); + impl CreateUploadRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateUploadRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateUploadRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateUploadRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateUploadRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateUploadRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateUploadRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateUploadRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `file_name` + #[must_use] + pub fn file_name(&self) -> &'_ str { + self.0.reborrow().file_name + } + /// Field 2: `content_type` + #[must_use] + pub fn content_type(&self) -> &'_ str { + self.0.reborrow().content_type + } + /// Field 3: `size_bytes` + #[must_use] + pub fn size_bytes(&self) -> i64 { + self.0.reborrow().size_bytes + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for CreateUploadRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateUploadRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateUploadRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for CreateUploadRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateUploadRequest { + type View<'a> = CreateUploadRequestView<'a>; + type ViewHandle = CreateUploadRequestOwnedView; + } + impl ::serde::Serialize for CreateUploadRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CreateUploadResponseView<'a> { + /// Field 1: `upload` + pub upload: ::buffa::MessageFieldView< + super::super::__buffa::view::UploadView<'a>, + >, + /// Pre-signed PUT target the client uploads the bytes to. + /// + /// Field 2: `upload_url` + pub upload_url: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CreateUploadResponseView<'a> { + type Owned = super::super::CreateUploadResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.upload.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.upload = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.upload_url = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CreateUploadResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CreateUploadResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CreateUploadResponse { + upload: match self.upload.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Upload, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + upload_url: self.upload_url.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CreateUploadResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.upload.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.upload.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.upload_url.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.upload_url) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.upload.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.upload.write_to(__cache, buf); + } + if !self.upload_url.is_empty() { + ::buffa::types::put_string_field(2u32, &self.upload_url, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CreateUploadResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.upload.as_option() { + __map.serialize_entry("upload", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.upload_url) { + __map.serialize_entry("uploadUrl", self.upload_url)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CreateUploadResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CreateUploadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CreateUploadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CreateUploadResponse"; + } + ::buffa::impl_default_view_instance!(CreateUploadResponseView); + ::buffa::impl_view_reborrow!(CreateUploadResponseView); + /** Self-contained, `'static` owned view of a `CreateUploadResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`CreateUploadResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CreateUploadResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CreateUploadResponseOwnedView( + ::buffa::OwnedView>, + ); + impl CreateUploadResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateUploadResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateUploadResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CreateUploadResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CreateUploadResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CreateUploadResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CreateUploadResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CreateUploadResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `upload` + #[must_use] + pub fn upload( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::UploadView<'_>, + > { + &self.0.reborrow().upload + } + /// Pre-signed PUT target the client uploads the bytes to. + /// + /// Field 2: `upload_url` + #[must_use] + pub fn upload_url(&self) -> &'_ str { + self.0.reborrow().upload_url + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for CreateUploadResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CreateUploadResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CreateUploadResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for CreateUploadResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CreateUploadResponse { + type View<'a> = CreateUploadResponseView<'a>; + type ViewHandle = CreateUploadResponseOwnedView; + } + impl ::serde::Serialize for CreateUploadResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CompleteUploadRequestView<'a> { + /// Field 1: `upload_id` + pub upload_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CompleteUploadRequestView<'a> { + type Owned = super::super::CompleteUploadRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.upload_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CompleteUploadRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CompleteUploadRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CompleteUploadRequest { + upload_id: self.upload_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CompleteUploadRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CompleteUploadRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.upload_id) { + __map.serialize_entry("uploadId", self.upload_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CompleteUploadRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CompleteUploadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.CompleteUploadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CompleteUploadRequest"; + } + ::buffa::impl_default_view_instance!(CompleteUploadRequestView); + ::buffa::impl_view_reborrow!(CompleteUploadRequestView); + /** Self-contained, `'static` owned view of a `CompleteUploadRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`CompleteUploadRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CompleteUploadRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CompleteUploadRequestOwnedView( + ::buffa::OwnedView>, + ); + impl CompleteUploadRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CompleteUploadRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CompleteUploadRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CompleteUploadRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CompleteUploadRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CompleteUploadRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CompleteUploadRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CompleteUploadRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `upload_id` + #[must_use] + pub fn upload_id(&self) -> &'_ str { + self.0.reborrow().upload_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for CompleteUploadRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CompleteUploadRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CompleteUploadRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for CompleteUploadRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CompleteUploadRequest { + type View<'a> = CompleteUploadRequestView<'a>; + type ViewHandle = CompleteUploadRequestOwnedView; + } + impl ::serde::Serialize for CompleteUploadRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct CompleteUploadResponseView<'a> { + /// Field 1: `upload` + pub upload: ::buffa::MessageFieldView< + super::super::__buffa::view::UploadView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for CompleteUploadResponseView<'a> { + type Owned = super::super::CompleteUploadResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.upload.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.upload = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CompleteUploadResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::CompleteUploadResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::CompleteUploadResponse { + upload: match self.upload.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Upload, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for CompleteUploadResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.upload.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.upload.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.upload.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.upload.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for CompleteUploadResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.upload.as_option() { + __map.serialize_entry("upload", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for CompleteUploadResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "CompleteUploadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.CompleteUploadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.CompleteUploadResponse"; + } + ::buffa::impl_default_view_instance!(CompleteUploadResponseView); + ::buffa::impl_view_reborrow!(CompleteUploadResponseView); + /** Self-contained, `'static` owned view of a `CompleteUploadResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`CompleteUploadResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`CompleteUploadResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct CompleteUploadResponseOwnedView( + ::buffa::OwnedView>, + ); + impl CompleteUploadResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CompleteUploadResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CompleteUploadResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::CompleteUploadResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + CompleteUploadResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`CompleteUploadResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &CompleteUploadResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CompleteUploadResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `upload` + #[must_use] + pub fn upload( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::UploadView<'_>, + > { + &self.0.reborrow().upload + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for CompleteUploadResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + CompleteUploadResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: CompleteUploadResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for CompleteUploadResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::CompleteUploadResponse { + type View<'a> = CompleteUploadResponseView<'a>; + type ViewHandle = CompleteUploadResponseOwnedView; + } + impl ::serde::Serialize for CompleteUploadResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetUploadRequestView<'a> { + /// Field 1: `upload_id` + pub upload_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetUploadRequestView<'a> { + type Owned = super::super::GetUploadRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.upload_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetUploadRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetUploadRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetUploadRequest { + upload_id: self.upload_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetUploadRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetUploadRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.upload_id) { + __map.serialize_entry("uploadId", self.upload_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetUploadRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetUploadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetUploadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUploadRequest"; + } + ::buffa::impl_default_view_instance!(GetUploadRequestView); + ::buffa::impl_view_reborrow!(GetUploadRequestView); + /** Self-contained, `'static` owned view of a `GetUploadRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetUploadRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetUploadRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetUploadRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetUploadRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUploadRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUploadRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetUploadRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUploadRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetUploadRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetUploadRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetUploadRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `upload_id` + #[must_use] + pub fn upload_id(&self) -> &'_ str { + self.0.reborrow().upload_id + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GetUploadRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + GetUploadRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetUploadRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GetUploadRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetUploadRequest { + type View<'a> = GetUploadRequestView<'a>; + type ViewHandle = GetUploadRequestOwnedView; + } + impl ::serde::Serialize for GetUploadRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetUploadResponseView<'a> { + /// Field 1: `upload` + pub upload: ::buffa::MessageFieldView< + super::super::__buffa::view::UploadView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetUploadResponseView<'a> { + type Owned = super::super::GetUploadResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.upload.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.upload = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetUploadResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetUploadResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetUploadResponse { + upload: match self.upload.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::Upload, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetUploadResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.upload.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.upload.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.upload.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.upload.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetUploadResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.upload.as_option() { + __map.serialize_entry("upload", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetUploadResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetUploadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetUploadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUploadResponse"; + } + ::buffa::impl_default_view_instance!(GetUploadResponseView); + ::buffa::impl_view_reborrow!(GetUploadResponseView); + /** Self-contained, `'static` owned view of a `GetUploadResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetUploadResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetUploadResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetUploadResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetUploadResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUploadResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUploadResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetUploadResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUploadResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetUploadResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetUploadResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetUploadResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `upload` + #[must_use] + pub fn upload( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::UploadView<'_>, + > { + &self.0.reborrow().upload + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GetUploadResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + GetUploadResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetUploadResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GetUploadResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetUploadResponse { + type View<'a> = GetUploadResponseView<'a>; + type ViewHandle = GetUploadResponseOwnedView; + } + impl ::serde::Serialize for GetUploadResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct DeleteUploadRequestView<'a> { + /// Field 1: `upload_id` + pub upload_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for DeleteUploadRequestView<'a> { + type Owned = super::super::DeleteUploadRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.upload_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::DeleteUploadRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::DeleteUploadRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::DeleteUploadRequest { + upload_id: self.upload_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for DeleteUploadRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.upload_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.upload_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.upload_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.upload_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for DeleteUploadRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.upload_id) { + __map.serialize_entry("uploadId", self.upload_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for DeleteUploadRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DeleteUploadRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.DeleteUploadRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteUploadRequest"; + } + ::buffa::impl_default_view_instance!(DeleteUploadRequestView); + ::buffa::impl_view_reborrow!(DeleteUploadRequestView); + /** Self-contained, `'static` owned view of a `DeleteUploadRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`DeleteUploadRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`DeleteUploadRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct DeleteUploadRequestOwnedView( + ::buffa::OwnedView>, + ); + impl DeleteUploadRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteUploadRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteUploadRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::DeleteUploadRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteUploadRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`DeleteUploadRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &DeleteUploadRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::DeleteUploadRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `upload_id` + #[must_use] + pub fn upload_id(&self) -> &'_ str { + self.0.reborrow().upload_id + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for DeleteUploadRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + DeleteUploadRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: DeleteUploadRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for DeleteUploadRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::DeleteUploadRequest { + type View<'a> = DeleteUploadRequestView<'a>; + type ViewHandle = DeleteUploadRequestOwnedView; + } + impl ::serde::Serialize for DeleteUploadRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct DeleteUploadResponseView<'a> { + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for DeleteUploadResponseView<'a> { + type Owned = super::super::DeleteUploadResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::DeleteUploadResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::DeleteUploadResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::DeleteUploadResponse { + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for DeleteUploadResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for DeleteUploadResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + __map.end() + } + } + impl<'a> ::buffa::MessageName for DeleteUploadResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "DeleteUploadResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.DeleteUploadResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.DeleteUploadResponse"; + } + ::buffa::impl_default_view_instance!(DeleteUploadResponseView); + ::buffa::impl_view_reborrow!(DeleteUploadResponseView); + /** Self-contained, `'static` owned view of a `DeleteUploadResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`DeleteUploadResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`DeleteUploadResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct DeleteUploadResponseOwnedView( + ::buffa::OwnedView>, + ); + impl DeleteUploadResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteUploadResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteUploadResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::DeleteUploadResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + DeleteUploadResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`DeleteUploadResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &DeleteUploadResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::DeleteUploadResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for DeleteUploadResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + DeleteUploadResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: DeleteUploadResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for DeleteUploadResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::DeleteUploadResponse { + type View<'a> = DeleteUploadResponseView<'a>; + type ViewHandle = DeleteUploadResponseOwnedView; + } + impl ::serde::Serialize for DeleteUploadResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetUserRequestView<'a> { + /// Field 1: `user_id` + pub user_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetUserRequestView<'a> { + type Owned = super::super::GetUserRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.user_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetUserRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetUserRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetUserRequest { + user_id: self.user_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetUserRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.user_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.user_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.user_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.user_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetUserRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.user_id) { + __map.serialize_entry("userId", self.user_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetUserRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetUserRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.GetUserRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUserRequest"; + } + ::buffa::impl_default_view_instance!(GetUserRequestView); + ::buffa::impl_view_reborrow!(GetUserRequestView); + /** Self-contained, `'static` owned view of a `GetUserRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetUserRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetUserRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetUserRequestOwnedView( + ::buffa::OwnedView>, + ); + impl GetUserRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUserRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUserRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetUserRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUserRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetUserRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetUserRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetUserRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `user_id` + #[must_use] + pub fn user_id(&self) -> &'_ str { + self.0.reborrow().user_id + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GetUserRequestOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + GetUserRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetUserRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GetUserRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetUserRequest { + type View<'a> = GetUserRequestView<'a>; + type ViewHandle = GetUserRequestOwnedView; + } + impl ::serde::Serialize for GetUserRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct GetUserResponseView<'a> { + /// Field 1: `user` + pub user: ::buffa::MessageFieldView< + super::super::__buffa::view::UserSummaryView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for GetUserResponseView<'a> { + type Owned = super::super::GetUserResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.user.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.user = ::buffa::MessageFieldView::set( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::GetUserResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::GetUserResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::GetUserResponse { + user: match self.user.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::UserSummary, + ::buffa::Inline, + >::some(v.to_owned_from_source(__buffa_src)?) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for GetUserResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.user.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.user.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.user.is_set() { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + self.user.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GetUserResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.user.as_option() { + __map.serialize_entry("user", __v)?; + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GetUserResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "GetUserResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.GetUserResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.GetUserResponse"; + } + ::buffa::impl_default_view_instance!(GetUserResponseView); + ::buffa::impl_view_reborrow!(GetUserResponseView); + /** Self-contained, `'static` owned view of a `GetUserResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`GetUserResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GetUserResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GetUserResponseOwnedView( + ::buffa::OwnedView>, + ); + impl GetUserResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUserResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUserResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::GetUserResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GetUserResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GetUserResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GetUserResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GetUserResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `user` + #[must_use] + pub fn user( + &self, + ) -> &::buffa::MessageFieldView< + super::super::__buffa::view::UserSummaryView<'_>, + > { + &self.0.reborrow().user + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GetUserResponseOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + GetUserResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GetUserResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GetUserResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::GetUserResponse { + type View<'a> = GetUserResponseView<'a>; + type ViewHandle = GetUserResponseOwnedView; + } + impl ::serde::Serialize for GetUserResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListWishlistRequestView<'a> { + /// Field 1: `page_token` + pub page_token: &'a str, + /// Field 2: `page_size` + pub page_size: i32, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListWishlistRequestView<'a> { + type Owned = super::super::ListWishlistRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.page_size = ::buffa::types::decode_int32(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListWishlistRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListWishlistRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListWishlistRequest { + page_token: self.page_token.to_string(), + page_size: self.page_size, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListWishlistRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.page_token) + as u64; + } + if self.page_size != 0i32 { + size + += 1u64 + + ::buffa::types::int32_encoded_len(self.page_size) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.page_token.is_empty() { + ::buffa::types::put_string_field(1u32, &self.page_token, buf); + } + if self.page_size != 0i32 { + ::buffa::types::put_int32_field(2u32, self.page_size, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListWishlistRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.page_token) { + __map.serialize_entry("pageToken", self.page_token)?; + } + if !::buffa::json_helpers::skip_if::is_zero_i32(&self.page_size) { + __map + .serialize_entry( + "pageSize", + &::buffa::json_helpers::ProtoJson(&self.page_size), + )?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListWishlistRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListWishlistRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.ListWishlistRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListWishlistRequest"; + } + ::buffa::impl_default_view_instance!(ListWishlistRequestView); + ::buffa::impl_view_reborrow!(ListWishlistRequestView); + /** Self-contained, `'static` owned view of a `ListWishlistRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListWishlistRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListWishlistRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListWishlistRequestOwnedView( + ::buffa::OwnedView>, + ); + impl ListWishlistRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListWishlistRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListWishlistRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListWishlistRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListWishlistRequestOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListWishlistRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListWishlistRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListWishlistRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `page_token` + #[must_use] + pub fn page_token(&self) -> &'_ str { + self.0.reborrow().page_token + } + /// Field 2: `page_size` + #[must_use] + pub fn page_size(&self) -> i32 { + self.0.reborrow().page_size + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListWishlistRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListWishlistRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListWishlistRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for ListWishlistRequestOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListWishlistRequest { + type View<'a> = ListWishlistRequestView<'a>; + type ViewHandle = ListWishlistRequestOwnedView; + } + impl ::serde::Serialize for ListWishlistRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct ListWishlistResponseView<'a> { + /// Field 1: `books` + pub books: ::buffa::RepeatedView< + 'a, + super::super::__buffa::view::BookView<'a>, + >, + /// Field 2: `next_page_token` + pub next_page_token: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for ListWishlistResponseView<'a> { + type Owned = super::super::ListWishlistResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.next_page_token = ::buffa::types::borrow_str(&mut cur)?; + } + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + ctx.register_element_memory( + ::core::mem::size_of::< + super::super::__buffa::view::BookView, + >(), + )?; + view.books + .push( + ::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ListWishlistResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::ListWishlistResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::ListWishlistResponse { + books: self + .books + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + next_page_token: self.next_page_token.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for ListWishlistResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + for v in &self.books { + let __slot = __cache.reserve(); + let inner_size = v.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; + } + if !self.next_page_token.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.next_page_token) + as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + for v in &self.books { + ::buffa::types::put_len_delimited_header( + 1u32, + u64::from(__cache.consume_next()), + buf, + ); + v.write_to(__cache, buf); + } + if !self.next_page_token.is_empty() { + ::buffa::types::put_string_field(2u32, &self.next_page_token, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for ListWishlistResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !self.books.is_empty() { + __map.serialize_entry("books", &*self.books)?; + } + if !::buffa::json_helpers::skip_if::is_empty_str(self.next_page_token) { + __map.serialize_entry("nextPageToken", self.next_page_token)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for ListWishlistResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "ListWishlistResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.ListWishlistResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.ListWishlistResponse"; + } + ::buffa::impl_default_view_instance!(ListWishlistResponseView); + ::buffa::impl_view_reborrow!(ListWishlistResponseView); + /** Self-contained, `'static` owned view of a `ListWishlistResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`ListWishlistResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`ListWishlistResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct ListWishlistResponseOwnedView( + ::buffa::OwnedView>, + ); + impl ListWishlistResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListWishlistResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListWishlistResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::ListWishlistResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + ListWishlistResponseOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`ListWishlistResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &ListWishlistResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListWishlistResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `books` + #[must_use] + pub fn books( + &self, + ) -> &::buffa::RepeatedView<'_, super::super::__buffa::view::BookView<'_>> { + &self.0.reborrow().books + } + /// Field 2: `next_page_token` + #[must_use] + pub fn next_page_token(&self) -> &'_ str { + self.0.reborrow().next_page_token + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for ListWishlistResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + ListWishlistResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: ListWishlistResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for ListWishlistResponseOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::ListWishlistResponse { + type View<'a> = ListWishlistResponseView<'a>; + type ViewHandle = ListWishlistResponseOwnedView; + } + impl ::serde::Serialize for ListWishlistResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct AddBookToWishlistRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for AddBookToWishlistRequestView<'a> { + type Owned = super::super::AddBookToWishlistRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::AddBookToWishlistRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::AddBookToWishlistRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::AddBookToWishlistRequest { + book_id: self.book_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for AddBookToWishlistRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for AddBookToWishlistRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for AddBookToWishlistRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "AddBookToWishlistRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.AddBookToWishlistRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.AddBookToWishlistRequest"; + } + ::buffa::impl_default_view_instance!(AddBookToWishlistRequestView); + ::buffa::impl_view_reborrow!(AddBookToWishlistRequestView); + /** Self-contained, `'static` owned view of a `AddBookToWishlistRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`AddBookToWishlistRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`AddBookToWishlistRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct AddBookToWishlistRequestOwnedView( + ::buffa::OwnedView>, + ); + impl AddBookToWishlistRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + AddBookToWishlistRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + AddBookToWishlistRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::AddBookToWishlistRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + AddBookToWishlistRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`AddBookToWishlistRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &AddBookToWishlistRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::AddBookToWishlistRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for AddBookToWishlistRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + AddBookToWishlistRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: AddBookToWishlistRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for AddBookToWishlistRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::AddBookToWishlistRequest { + type View<'a> = AddBookToWishlistRequestView<'a>; + type ViewHandle = AddBookToWishlistRequestOwnedView; + } + impl ::serde::Serialize for AddBookToWishlistRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct AddBookToWishlistResponseView<'a> { + /// Field 1: `added` + pub added: bool, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for AddBookToWishlistResponseView<'a> { + type Owned = super::super::AddBookToWishlistResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.added = ::buffa::types::decode_bool(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::AddBookToWishlistResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::AddBookToWishlistResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::AddBookToWishlistResponse { + added: self.added, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for AddBookToWishlistResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.added { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.added { + ::buffa::types::put_bool_field(1u32, self.added, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for AddBookToWishlistResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if self.added { + __map.serialize_entry("added", &self.added)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for AddBookToWishlistResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "AddBookToWishlistResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.AddBookToWishlistResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.AddBookToWishlistResponse"; + } + ::buffa::impl_default_view_instance!(AddBookToWishlistResponseView); + ::buffa::impl_view_reborrow!(AddBookToWishlistResponseView); + /** Self-contained, `'static` owned view of a `AddBookToWishlistResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`AddBookToWishlistResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`AddBookToWishlistResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct AddBookToWishlistResponseOwnedView( + ::buffa::OwnedView>, + ); + impl AddBookToWishlistResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + AddBookToWishlistResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + AddBookToWishlistResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::AddBookToWishlistResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + AddBookToWishlistResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`AddBookToWishlistResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &AddBookToWishlistResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::AddBookToWishlistResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `added` + #[must_use] + pub fn added(&self) -> bool { + self.0.reborrow().added + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for AddBookToWishlistResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + AddBookToWishlistResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: AddBookToWishlistResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for AddBookToWishlistResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::AddBookToWishlistResponse { + type View<'a> = AddBookToWishlistResponseView<'a>; + type ViewHandle = AddBookToWishlistResponseOwnedView; + } + impl ::serde::Serialize for AddBookToWishlistResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct RemoveBookFromWishlistRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for RemoveBookFromWishlistRequestView<'a> { + type Owned = super::super::RemoveBookFromWishlistRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::RemoveBookFromWishlistRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::RemoveBookFromWishlistRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::RemoveBookFromWishlistRequest { + book_id: self.book_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for RemoveBookFromWishlistRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for RemoveBookFromWishlistRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for RemoveBookFromWishlistRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "RemoveBookFromWishlistRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.RemoveBookFromWishlistRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RemoveBookFromWishlistRequest"; + } + ::buffa::impl_default_view_instance!(RemoveBookFromWishlistRequestView); + ::buffa::impl_view_reborrow!(RemoveBookFromWishlistRequestView); + /** Self-contained, `'static` owned view of a `RemoveBookFromWishlistRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`RemoveBookFromWishlistRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`RemoveBookFromWishlistRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct RemoveBookFromWishlistRequestOwnedView( + ::buffa::OwnedView>, + ); + impl RemoveBookFromWishlistRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RemoveBookFromWishlistRequestOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RemoveBookFromWishlistRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::RemoveBookFromWishlistRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RemoveBookFromWishlistRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`RemoveBookFromWishlistRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &RemoveBookFromWishlistRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::RemoveBookFromWishlistRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for RemoveBookFromWishlistRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + RemoveBookFromWishlistRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: RemoveBookFromWishlistRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for RemoveBookFromWishlistRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::RemoveBookFromWishlistRequest { + type View<'a> = RemoveBookFromWishlistRequestView<'a>; + type ViewHandle = RemoveBookFromWishlistRequestOwnedView; + } + impl ::serde::Serialize for RemoveBookFromWishlistRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct RemoveBookFromWishlistResponseView<'a> { + /// Field 1: `removed` + pub removed: bool, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for RemoveBookFromWishlistResponseView<'a> { + type Owned = super::super::RemoveBookFromWishlistResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.removed = ::buffa::types::decode_bool(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::RemoveBookFromWishlistResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::RemoveBookFromWishlistResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::RemoveBookFromWishlistResponse { + removed: self.removed, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for RemoveBookFromWishlistResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.removed { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.removed { + ::buffa::types::put_bool_field(1u32, self.removed, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for RemoveBookFromWishlistResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if self.removed { + __map.serialize_entry("removed", &self.removed)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for RemoveBookFromWishlistResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "RemoveBookFromWishlistResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.RemoveBookFromWishlistResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.RemoveBookFromWishlistResponse"; + } + ::buffa::impl_default_view_instance!(RemoveBookFromWishlistResponseView); + ::buffa::impl_view_reborrow!(RemoveBookFromWishlistResponseView); + /** Self-contained, `'static` owned view of a `RemoveBookFromWishlistResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`RemoveBookFromWishlistResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`RemoveBookFromWishlistResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct RemoveBookFromWishlistResponseOwnedView( + ::buffa::OwnedView>, + ); + impl RemoveBookFromWishlistResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RemoveBookFromWishlistResponseOwnedView( + ::buffa::OwnedView::decode(bytes)?, + ), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RemoveBookFromWishlistResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::RemoveBookFromWishlistResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + RemoveBookFromWishlistResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`RemoveBookFromWishlistResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &RemoveBookFromWishlistResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message( + &self, + ) -> super::super::RemoveBookFromWishlistResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `removed` + #[must_use] + pub fn removed(&self) -> bool { + self.0.reborrow().removed + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for RemoveBookFromWishlistResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + RemoveBookFromWishlistResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: RemoveBookFromWishlistResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for RemoveBookFromWishlistResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::RemoveBookFromWishlistResponse { + type View<'a> = RemoveBookFromWishlistResponseView<'a>; + type ViewHandle = RemoveBookFromWishlistResponseOwnedView; + } + impl ::serde::Serialize for RemoveBookFromWishlistResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct IsBookInWishlistRequestView<'a> { + /// Field 1: `book_id` + pub book_id: &'a str, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for IsBookInWishlistRequestView<'a> { + type Owned = super::super::IsBookInWishlistRequest; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.book_id = ::buffa::types::borrow_str(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::IsBookInWishlistRequest, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::IsBookInWishlistRequest, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::IsBookInWishlistRequest { + book_id: self.book_id.to_string(), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for IsBookInWishlistRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if !self.book_id.is_empty() { + size + += 1u64 + + ::buffa::types::string_encoded_len(&self.book_id) as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if !self.book_id.is_empty() { + ::buffa::types::put_string_field(1u32, &self.book_id, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for IsBookInWishlistRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.book_id) { + __map.serialize_entry("bookId", self.book_id)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for IsBookInWishlistRequestView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "IsBookInWishlistRequest"; + const FULL_NAME: &'static str = "bookbridge.v1.IsBookInWishlistRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.IsBookInWishlistRequest"; + } + ::buffa::impl_default_view_instance!(IsBookInWishlistRequestView); + ::buffa::impl_view_reborrow!(IsBookInWishlistRequestView); + /** Self-contained, `'static` owned view of a `IsBookInWishlistRequest` message. + + Wraps [`::buffa::OwnedView`]`<`[`IsBookInWishlistRequestView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`IsBookInWishlistRequestView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct IsBookInWishlistRequestOwnedView( + ::buffa::OwnedView>, + ); + impl IsBookInWishlistRequestOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + IsBookInWishlistRequestOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + IsBookInWishlistRequestOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::IsBookInWishlistRequest, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + IsBookInWishlistRequestOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`IsBookInWishlistRequestView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &IsBookInWishlistRequestView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::IsBookInWishlistRequest { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `book_id` + #[must_use] + pub fn book_id(&self) -> &'_ str { + self.0.reborrow().book_id + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for IsBookInWishlistRequestOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + IsBookInWishlistRequestOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: IsBookInWishlistRequestOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for IsBookInWishlistRequestOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::IsBookInWishlistRequest { + type View<'a> = IsBookInWishlistRequestView<'a>; + type ViewHandle = IsBookInWishlistRequestOwnedView; + } + impl ::serde::Serialize for IsBookInWishlistRequestOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + #[derive(Clone, Debug, Default)] + pub struct IsBookInWishlistResponseView<'a> { + /// Field 1: `is_favorite` + pub is_favorite: bool, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, + } + impl<'a> ::buffa::MessageView<'a> for IsBookInWishlistResponseView<'a> { + type Owned = super::super::IsBookInWishlistResponse; + fn decode_view( + buf: &'a [u8], + ) -> ::core::result::Result { + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), + ) + } + fn decode_view_with_ctx( + buf: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result { + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.is_favorite = ::buffa::types::decode_bool(&mut cur)?; + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) + } + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::IsBookInWishlistResponse, + ::buffa::DecodeError, + > { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> ::core::result::Result< + super::super::IsBookInWishlistResponse, + ::buffa::DecodeError, + > { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + ::core::result::Result::Ok(super::super::IsBookInWishlistResponse { + is_favorite: self.is_favorite, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned()? + .into(), + ..::core::default::Default::default() + }) + } + } + impl<'a> ::buffa::ViewEncode<'a> for IsBookInWishlistResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, _cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u64; + if self.is_favorite { + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; + } + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + _cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::EncodeSink, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.is_favorite { + ::buffa::types::put_bool_field(1u32, self.is_favorite, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for IsBookInWishlistResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if self.is_favorite { + __map.serialize_entry("isFavorite", &self.is_favorite)?; + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for IsBookInWishlistResponseView<'a> { + const PACKAGE: &'static str = "bookbridge.v1"; + const NAME: &'static str = "IsBookInWishlistResponse"; + const FULL_NAME: &'static str = "bookbridge.v1.IsBookInWishlistResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/bookbridge.v1.IsBookInWishlistResponse"; + } + ::buffa::impl_default_view_instance!(IsBookInWishlistResponseView); + ::buffa::impl_view_reborrow!(IsBookInWishlistResponseView); + /** Self-contained, `'static` owned view of a `IsBookInWishlistResponse` message. + + Wraps [`::buffa::OwnedView`]`<`[`IsBookInWishlistResponseView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`IsBookInWishlistResponseView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct IsBookInWishlistResponseOwnedView( + ::buffa::OwnedView>, + ); + impl IsBookInWishlistResponseOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + IsBookInWishlistResponseOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + IsBookInWishlistResponseOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::IsBookInWishlistResponse, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + IsBookInWishlistResponseOwnedView( + ::buffa::OwnedView::from_owned(msg)?, + ), + ) + } + /// Borrow the full [`IsBookInWishlistResponseView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &IsBookInWishlistResponseView<'_> { + self.0.reborrow() + } + /// Convert to the owned message type. + /// + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::IsBookInWishlistResponse { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// Field 1: `is_favorite` + #[must_use] + pub fn is_favorite(&self) -> bool { + self.0.reborrow().is_favorite + } + } + impl ::core::convert::From< + ::buffa::OwnedView>, + > for IsBookInWishlistResponseOwnedView { + fn from( + inner: ::buffa::OwnedView>, + ) -> Self { + IsBookInWishlistResponseOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: IsBookInWishlistResponseOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef< + ::buffa::OwnedView>, + > for IsBookInWishlistResponseOwnedView { + fn as_ref( + &self, + ) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::IsBookInWishlistResponse { + type View<'a> = IsBookInWishlistResponseView<'a>; + type ViewHandle = IsBookInWishlistResponseOwnedView; + } + impl ::serde::Serialize for IsBookInWishlistResponseOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } + pub mod oneof { + #[allow(unused_imports)] + use super::*; + pub mod sign_in_request { + #[allow(unused_imports)] + use super::*; + #[derive(Clone, Debug)] + pub enum Identifier<'a> { + Email(&'a str), + Phone(&'a str), + } + } + pub mod stream_conversations_response { + #[allow(unused_imports)] + use super::*; + #[derive(Clone, Debug)] + pub enum Event<'a> { + Upserted( + ::buffa::alloc::boxed::Box< + super::super::super::super::__buffa::view::ConversationView< + 'a, + >, + >, + ), + MessageCreated( + ::buffa::alloc::boxed::Box< + super::super::super::super::__buffa::view::MessageView<'a>, + >, + ), + } + } + } + } + pub mod oneof { + #[allow(unused_imports)] + use super::*; + pub mod sign_in_request { + #[allow(unused_imports)] + use super::*; + #[derive(Clone, PartialEq, Debug)] + pub enum Identifier { + Email(::buffa::alloc::string::String), + Phone(::buffa::alloc::string::String), + } + impl ::buffa::Oneof for Identifier {} + impl ::serde::Serialize for Identifier { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + use ::serde::ser::SerializeMap; + let mut map = s.serialize_map(Some(1))?; + match self { + Self::Email(v) => { + map.serialize_entry("email", v)?; + } + Self::Phone(v) => { + map.serialize_entry("phone", v)?; + } + } + map.end() + } + } + } + pub mod stream_conversations_response { + #[allow(unused_imports)] + use super::*; + #[derive(Clone, PartialEq, Debug)] + pub enum Event { + Upserted(::buffa::alloc::boxed::Box), + MessageCreated(::buffa::alloc::boxed::Box), + } + impl ::buffa::Oneof for Event {} + impl From for Event { + fn from(v: super::super::super::Conversation) -> Self { + Self::Upserted(::buffa::alloc::boxed::Box::new(v)) + } + } + impl From + for ::core::option::Option { + fn from(v: super::super::super::Conversation) -> Self { + Self::Some(Event::from(v)) + } + } + impl From for Event { + fn from(v: super::super::super::Message) -> Self { + Self::MessageCreated(::buffa::alloc::boxed::Box::new(v)) + } + } + impl From for ::core::option::Option { + fn from(v: super::super::super::Message) -> Self { + Self::Some(Event::from(v)) + } + } + impl ::serde::Serialize for Event { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + use ::serde::ser::SerializeMap; + let mut map = s.serialize_map(Some(1))?; + match self { + Self::Upserted(v) => { + map.serialize_entry("upserted", &**v)?; + } + Self::MessageCreated(v) => { + map.serialize_entry("messageCreated", &**v)?; + } + } + map.end() + } + } + } + } + /// Register this package's `Any` type entries and extension entries. + pub fn register_types(reg: &mut ::buffa::type_registry::TypeRegistry) { + reg.register_json_any(super::__USER_JSON_ANY); + reg.register_json_any(super::__SESSION_JSON_ANY); + reg.register_json_any(super::__SIGN_UP_REQUEST_JSON_ANY); + reg.register_json_any(super::__SIGN_UP_RESPONSE_JSON_ANY); + reg.register_json_any(super::__SIGN_IN_REQUEST_JSON_ANY); + reg.register_json_any(super::__SIGN_IN_RESPONSE_JSON_ANY); + reg.register_json_any(super::__SIGN_IN_WITH_GOOGLE_REQUEST_JSON_ANY); + reg.register_json_any(super::__SIGN_IN_WITH_GOOGLE_RESPONSE_JSON_ANY); + reg.register_json_any(super::__REFRESH_SESSION_REQUEST_JSON_ANY); + reg.register_json_any(super::__REFRESH_SESSION_RESPONSE_JSON_ANY); + reg.register_json_any(super::__SIGN_OUT_REQUEST_JSON_ANY); + reg.register_json_any(super::__SIGN_OUT_RESPONSE_JSON_ANY); + reg.register_json_any(super::__GET_CURRENT_USER_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_CURRENT_USER_RESPONSE_JSON_ANY); + reg.register_json_any(super::__UPDATE_CURRENT_USER_REQUEST_JSON_ANY); + reg.register_json_any(super::__UPDATE_CURRENT_USER_RESPONSE_JSON_ANY); + reg.register_json_any(super::__SEND_PASSWORD_RESET_REQUEST_JSON_ANY); + reg.register_json_any(super::__SEND_PASSWORD_RESET_RESPONSE_JSON_ANY); + reg.register_json_any(super::__SET_DEVICE_TOKEN_REQUEST_JSON_ANY); + reg.register_json_any(super::__SET_DEVICE_TOKEN_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LAT_LNG_JSON_ANY); + reg.register_json_any(super::__USER_SUMMARY_JSON_ANY); + reg.register_json_any(super::__BOOK_CATEGORY_JSON_ANY); + reg.register_json_any(super::__BOOK_PICTURE_JSON_ANY); + reg.register_json_any(super::__BOOK_JSON_ANY); + reg.register_json_any(super::__LIST_CATEGORIES_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_CATEGORIES_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LIST_BOOKS_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_BOOKS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__SEARCH_BOOKS_REQUEST_JSON_ANY); + reg.register_json_any(super::__SEARCH_BOOKS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__GET_BOOK_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_BOOK_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LIST_BOOKS_BY_SELLER_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_BOOKS_BY_SELLER_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LIST_MY_BOOKS_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_MY_BOOKS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__CREATE_BOOK_REQUEST_JSON_ANY); + reg.register_json_any(super::__CREATE_BOOK_RESPONSE_JSON_ANY); + reg.register_json_any(super::__UPDATE_BOOK_REQUEST_JSON_ANY); + reg.register_json_any(super::__UPDATE_BOOK_RESPONSE_JSON_ANY); + reg.register_json_any(super::__DELETE_BOOK_REQUEST_JSON_ANY); + reg.register_json_any(super::__DELETE_BOOK_RESPONSE_JSON_ANY); + reg.register_json_any(super::__BOOST_JSON_ANY); + reg.register_json_any(super::__CREATE_BOOST_REQUEST_JSON_ANY); + reg.register_json_any(super::__CREATE_BOOST_RESPONSE_JSON_ANY); + reg.register_json_any(super::__GET_BOOST_STATUS_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_BOOST_STATUS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__PAYMENT_OUTCOME_JSON_ANY); + reg.register_json_any(super::__CREATE_DONATION_REQUEST_JSON_ANY); + reg.register_json_any(super::__DONATION_JSON_ANY); + reg.register_json_any(super::__CREATE_DONATION_RESPONSE_JSON_ANY); + reg.register_json_any(super::__MESSAGE_JSON_ANY); + reg.register_json_any(super::__UPLOAD_ATTACHMENT_JSON_ANY); + reg.register_json_any(super::__CONVERSATION_JSON_ANY); + reg.register_json_any(super::__BOOK_SUMMARY_JSON_ANY); + reg.register_json_any(super::__LIST_CONVERSATIONS_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_CONVERSATIONS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__GET_OR_CREATE_CONVERSATION_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_OR_CREATE_CONVERSATION_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LIST_MESSAGES_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_MESSAGES_RESPONSE_JSON_ANY); + reg.register_json_any(super::__SEND_MESSAGE_REQUEST_JSON_ANY); + reg.register_json_any(super::__SEND_MESSAGE_RESPONSE_JSON_ANY); + reg.register_json_any(super::__MARK_MESSAGES_READ_REQUEST_JSON_ANY); + reg.register_json_any(super::__MARK_MESSAGES_READ_RESPONSE_JSON_ANY); + reg.register_json_any(super::__STREAM_CONVERSATIONS_REQUEST_JSON_ANY); + reg.register_json_any(super::__STREAM_CONVERSATIONS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__MEETUP_LOCATION_JSON_ANY); + reg.register_json_any(super::__LIST_MEETUP_LOCATIONS_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_MEETUP_LOCATIONS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__GET_MEETUP_LOCATION_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_MEETUP_LOCATION_RESPONSE_JSON_ANY); + reg.register_json_any(super::__NOTIFICATION_JSON_ANY); + reg.register_json_any(super::__LIST_NOTIFICATIONS_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_NOTIFICATIONS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__MARK_NOTIFICATION_READ_REQUEST_JSON_ANY); + reg.register_json_any(super::__MARK_NOTIFICATION_READ_RESPONSE_JSON_ANY); + reg.register_json_any(super::__MARK_ALL_NOTIFICATIONS_READ_REQUEST_JSON_ANY); + reg.register_json_any(super::__MARK_ALL_NOTIFICATIONS_READ_RESPONSE_JSON_ANY); + reg.register_json_any(super::__STREAM_NOTIFICATIONS_REQUEST_JSON_ANY); + reg.register_json_any(super::__STREAM_NOTIFICATIONS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__PAYMENT_JSON_ANY); + reg.register_json_any(super::__PURCHASE_JSON_ANY); + reg.register_json_any(super::__BOOK_PURCHASE_DETAILS_JSON_ANY); + reg.register_json_any(super::__CREATE_BOOK_PURCHASE_REQUEST_JSON_ANY); + reg.register_json_any(super::__CREATE_BOOK_PURCHASE_RESPONSE_JSON_ANY); + reg.register_json_any(super::__GET_PURCHASE_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_PURCHASE_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LIST_MY_PURCHASES_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_MY_PURCHASES_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LIST_MY_SALES_REQUEST_JSON_ANY); + reg.register_json_any(super::__SALE_JSON_ANY); + reg.register_json_any(super::__LIST_MY_SALES_RESPONSE_JSON_ANY); + reg.register_json_any(super::__CONFIRM_RECEIPT_REQUEST_JSON_ANY); + reg.register_json_any(super::__CONFIRM_RECEIPT_RESPONSE_JSON_ANY); + reg.register_json_any(super::__DISPUTE_PURCHASE_REQUEST_JSON_ANY); + reg.register_json_any(super::__DISPUTE_PURCHASE_RESPONSE_JSON_ANY); + reg.register_json_any(super::__REVIEW_JSON_ANY); + reg.register_json_any(super::__CREATE_REVIEW_REQUEST_JSON_ANY); + reg.register_json_any(super::__CREATE_REVIEW_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LIST_USER_REVIEWS_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_USER_REVIEWS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__HAS_REVIEWED_TRANSACTION_REQUEST_JSON_ANY); + reg.register_json_any(super::__HAS_REVIEWED_TRANSACTION_RESPONSE_JSON_ANY); + reg.register_json_any(super::__PLATFORM_STATS_JSON_ANY); + reg.register_json_any(super::__GET_PLATFORM_STATS_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_PLATFORM_STATS_RESPONSE_JSON_ANY); + reg.register_json_any(super::__UPLOAD_JSON_ANY); + reg.register_json_any(super::__CREATE_UPLOAD_REQUEST_JSON_ANY); + reg.register_json_any(super::__CREATE_UPLOAD_RESPONSE_JSON_ANY); + reg.register_json_any(super::__COMPLETE_UPLOAD_REQUEST_JSON_ANY); + reg.register_json_any(super::__COMPLETE_UPLOAD_RESPONSE_JSON_ANY); + reg.register_json_any(super::__GET_UPLOAD_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_UPLOAD_RESPONSE_JSON_ANY); + reg.register_json_any(super::__DELETE_UPLOAD_REQUEST_JSON_ANY); + reg.register_json_any(super::__DELETE_UPLOAD_RESPONSE_JSON_ANY); + reg.register_json_any(super::__GET_USER_REQUEST_JSON_ANY); + reg.register_json_any(super::__GET_USER_RESPONSE_JSON_ANY); + reg.register_json_any(super::__LIST_WISHLIST_REQUEST_JSON_ANY); + reg.register_json_any(super::__LIST_WISHLIST_RESPONSE_JSON_ANY); + reg.register_json_any(super::__ADD_BOOK_TO_WISHLIST_REQUEST_JSON_ANY); + reg.register_json_any(super::__ADD_BOOK_TO_WISHLIST_RESPONSE_JSON_ANY); + reg.register_json_any(super::__REMOVE_BOOK_FROM_WISHLIST_REQUEST_JSON_ANY); + reg.register_json_any(super::__REMOVE_BOOK_FROM_WISHLIST_RESPONSE_JSON_ANY); + reg.register_json_any(super::__IS_BOOK_IN_WISHLIST_REQUEST_JSON_ANY); + reg.register_json_any(super::__IS_BOOK_IN_WISHLIST_RESPONSE_JSON_ANY); + } +} +#[doc(inline)] +pub use self::__buffa::view::UserView; +#[doc(inline)] +pub use self::__buffa::view::UserOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SessionView; +#[doc(inline)] +pub use self::__buffa::view::SessionOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SignUpRequestView; +#[doc(inline)] +pub use self::__buffa::view::SignUpRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SignUpResponseView; +#[doc(inline)] +pub use self::__buffa::view::SignUpResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SignInRequestView; +#[doc(inline)] +pub use self::__buffa::view::SignInRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SignInResponseView; +#[doc(inline)] +pub use self::__buffa::view::SignInResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SignInWithGoogleRequestView; +#[doc(inline)] +pub use self::__buffa::view::SignInWithGoogleRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SignInWithGoogleResponseView; +#[doc(inline)] +pub use self::__buffa::view::SignInWithGoogleResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::RefreshSessionRequestView; +#[doc(inline)] +pub use self::__buffa::view::RefreshSessionRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::RefreshSessionResponseView; +#[doc(inline)] +pub use self::__buffa::view::RefreshSessionResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SignOutRequestView; +#[doc(inline)] +pub use self::__buffa::view::SignOutRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SignOutResponseView; +#[doc(inline)] +pub use self::__buffa::view::SignOutResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetCurrentUserRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetCurrentUserRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetCurrentUserResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetCurrentUserResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::UpdateCurrentUserRequestView; +#[doc(inline)] +pub use self::__buffa::view::UpdateCurrentUserRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::UpdateCurrentUserResponseView; +#[doc(inline)] +pub use self::__buffa::view::UpdateCurrentUserResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SendPasswordResetRequestView; +#[doc(inline)] +pub use self::__buffa::view::SendPasswordResetRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SendPasswordResetResponseView; +#[doc(inline)] +pub use self::__buffa::view::SendPasswordResetResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SetDeviceTokenRequestView; +#[doc(inline)] +pub use self::__buffa::view::SetDeviceTokenRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SetDeviceTokenResponseView; +#[doc(inline)] +pub use self::__buffa::view::SetDeviceTokenResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::LatLngView; +#[doc(inline)] +pub use self::__buffa::view::LatLngOwnedView; +#[doc(inline)] +pub use self::__buffa::view::UserSummaryView; +#[doc(inline)] +pub use self::__buffa::view::UserSummaryOwnedView; +#[doc(inline)] +pub use self::__buffa::view::BookCategoryView; +#[doc(inline)] +pub use self::__buffa::view::BookCategoryOwnedView; +#[doc(inline)] +pub use self::__buffa::view::BookPictureView; +#[doc(inline)] +pub use self::__buffa::view::BookPictureOwnedView; +#[doc(inline)] +pub use self::__buffa::view::BookView; +#[doc(inline)] +pub use self::__buffa::view::BookOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListCategoriesRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListCategoriesRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListCategoriesResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListCategoriesResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListBooksRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListBooksRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListBooksResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListBooksResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SearchBooksRequestView; +#[doc(inline)] +pub use self::__buffa::view::SearchBooksRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SearchBooksResponseView; +#[doc(inline)] +pub use self::__buffa::view::SearchBooksResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetBookRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetBookRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetBookResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetBookResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListBooksBySellerRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListBooksBySellerRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListBooksBySellerResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListBooksBySellerResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMyBooksRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListMyBooksRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMyBooksResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListMyBooksResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateBookRequestView; +#[doc(inline)] +pub use self::__buffa::view::CreateBookRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateBookResponseView; +#[doc(inline)] +pub use self::__buffa::view::CreateBookResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::UpdateBookRequestView; +#[doc(inline)] +pub use self::__buffa::view::UpdateBookRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::UpdateBookResponseView; +#[doc(inline)] +pub use self::__buffa::view::UpdateBookResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::DeleteBookRequestView; +#[doc(inline)] +pub use self::__buffa::view::DeleteBookRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::DeleteBookResponseView; +#[doc(inline)] +pub use self::__buffa::view::DeleteBookResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::BoostView; +#[doc(inline)] +pub use self::__buffa::view::BoostOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateBoostRequestView; +#[doc(inline)] +pub use self::__buffa::view::CreateBoostRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateBoostResponseView; +#[doc(inline)] +pub use self::__buffa::view::CreateBoostResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetBoostStatusRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetBoostStatusRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetBoostStatusResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetBoostStatusResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::PaymentOutcomeView; +#[doc(inline)] +pub use self::__buffa::view::PaymentOutcomeOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateDonationRequestView; +#[doc(inline)] +pub use self::__buffa::view::CreateDonationRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::DonationView; +#[doc(inline)] +pub use self::__buffa::view::DonationOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateDonationResponseView; +#[doc(inline)] +pub use self::__buffa::view::CreateDonationResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::MessageView; +#[doc(inline)] +pub use self::__buffa::view::MessageOwnedView; +#[doc(inline)] +pub use self::__buffa::view::UploadAttachmentView; +#[doc(inline)] +pub use self::__buffa::view::UploadAttachmentOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ConversationView; +#[doc(inline)] +pub use self::__buffa::view::ConversationOwnedView; +#[doc(inline)] +pub use self::__buffa::view::BookSummaryView; +#[doc(inline)] +pub use self::__buffa::view::BookSummaryOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListConversationsRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListConversationsRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListConversationsResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListConversationsResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetOrCreateConversationRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetOrCreateConversationRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetOrCreateConversationResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetOrCreateConversationResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMessagesRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListMessagesRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMessagesResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListMessagesResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SendMessageRequestView; +#[doc(inline)] +pub use self::__buffa::view::SendMessageRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SendMessageResponseView; +#[doc(inline)] +pub use self::__buffa::view::SendMessageResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::MarkMessagesReadRequestView; +#[doc(inline)] +pub use self::__buffa::view::MarkMessagesReadRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::MarkMessagesReadResponseView; +#[doc(inline)] +pub use self::__buffa::view::MarkMessagesReadResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::StreamConversationsRequestView; +#[doc(inline)] +pub use self::__buffa::view::StreamConversationsRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::StreamConversationsResponseView; +#[doc(inline)] +pub use self::__buffa::view::StreamConversationsResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::MeetupLocationView; +#[doc(inline)] +pub use self::__buffa::view::MeetupLocationOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMeetupLocationsRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListMeetupLocationsRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMeetupLocationsResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListMeetupLocationsResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetMeetupLocationRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetMeetupLocationRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetMeetupLocationResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetMeetupLocationResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::NotificationView; +#[doc(inline)] +pub use self::__buffa::view::NotificationOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListNotificationsRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListNotificationsRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListNotificationsResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListNotificationsResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::MarkNotificationReadRequestView; +#[doc(inline)] +pub use self::__buffa::view::MarkNotificationReadRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::MarkNotificationReadResponseView; +#[doc(inline)] +pub use self::__buffa::view::MarkNotificationReadResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::MarkAllNotificationsReadRequestView; +#[doc(inline)] +pub use self::__buffa::view::MarkAllNotificationsReadRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::MarkAllNotificationsReadResponseView; +#[doc(inline)] +pub use self::__buffa::view::MarkAllNotificationsReadResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::StreamNotificationsRequestView; +#[doc(inline)] +pub use self::__buffa::view::StreamNotificationsRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::StreamNotificationsResponseView; +#[doc(inline)] +pub use self::__buffa::view::StreamNotificationsResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::PaymentView; +#[doc(inline)] +pub use self::__buffa::view::PaymentOwnedView; +#[doc(inline)] +pub use self::__buffa::view::PurchaseView; +#[doc(inline)] +pub use self::__buffa::view::PurchaseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::BookPurchaseDetailsView; +#[doc(inline)] +pub use self::__buffa::view::BookPurchaseDetailsOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateBookPurchaseRequestView; +#[doc(inline)] +pub use self::__buffa::view::CreateBookPurchaseRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateBookPurchaseResponseView; +#[doc(inline)] +pub use self::__buffa::view::CreateBookPurchaseResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetPurchaseRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetPurchaseRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetPurchaseResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetPurchaseResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMyPurchasesRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListMyPurchasesRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMyPurchasesResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListMyPurchasesResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMySalesRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListMySalesRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::SaleView; +#[doc(inline)] +pub use self::__buffa::view::SaleOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListMySalesResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListMySalesResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ConfirmReceiptRequestView; +#[doc(inline)] +pub use self::__buffa::view::ConfirmReceiptRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ConfirmReceiptResponseView; +#[doc(inline)] +pub use self::__buffa::view::ConfirmReceiptResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::DisputePurchaseRequestView; +#[doc(inline)] +pub use self::__buffa::view::DisputePurchaseRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::DisputePurchaseResponseView; +#[doc(inline)] +pub use self::__buffa::view::DisputePurchaseResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ReviewView; +#[doc(inline)] +pub use self::__buffa::view::ReviewOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateReviewRequestView; +#[doc(inline)] +pub use self::__buffa::view::CreateReviewRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateReviewResponseView; +#[doc(inline)] +pub use self::__buffa::view::CreateReviewResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListUserReviewsRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListUserReviewsRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListUserReviewsResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListUserReviewsResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::HasReviewedTransactionRequestView; +#[doc(inline)] +pub use self::__buffa::view::HasReviewedTransactionRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::HasReviewedTransactionResponseView; +#[doc(inline)] +pub use self::__buffa::view::HasReviewedTransactionResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::PlatformStatsView; +#[doc(inline)] +pub use self::__buffa::view::PlatformStatsOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetPlatformStatsRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetPlatformStatsRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetPlatformStatsResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetPlatformStatsResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::UploadView; +#[doc(inline)] +pub use self::__buffa::view::UploadOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateUploadRequestView; +#[doc(inline)] +pub use self::__buffa::view::CreateUploadRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CreateUploadResponseView; +#[doc(inline)] +pub use self::__buffa::view::CreateUploadResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CompleteUploadRequestView; +#[doc(inline)] +pub use self::__buffa::view::CompleteUploadRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::CompleteUploadResponseView; +#[doc(inline)] +pub use self::__buffa::view::CompleteUploadResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetUploadRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetUploadRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetUploadResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetUploadResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::DeleteUploadRequestView; +#[doc(inline)] +pub use self::__buffa::view::DeleteUploadRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::DeleteUploadResponseView; +#[doc(inline)] +pub use self::__buffa::view::DeleteUploadResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetUserRequestView; +#[doc(inline)] +pub use self::__buffa::view::GetUserRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::GetUserResponseView; +#[doc(inline)] +pub use self::__buffa::view::GetUserResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListWishlistRequestView; +#[doc(inline)] +pub use self::__buffa::view::ListWishlistRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::ListWishlistResponseView; +#[doc(inline)] +pub use self::__buffa::view::ListWishlistResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::AddBookToWishlistRequestView; +#[doc(inline)] +pub use self::__buffa::view::AddBookToWishlistRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::AddBookToWishlistResponseView; +#[doc(inline)] +pub use self::__buffa::view::AddBookToWishlistResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::RemoveBookFromWishlistRequestView; +#[doc(inline)] +pub use self::__buffa::view::RemoveBookFromWishlistRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::RemoveBookFromWishlistResponseView; +#[doc(inline)] +pub use self::__buffa::view::RemoveBookFromWishlistResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::view::IsBookInWishlistRequestView; +#[doc(inline)] +pub use self::__buffa::view::IsBookInWishlistRequestOwnedView; +#[doc(inline)] +pub use self::__buffa::view::IsBookInWishlistResponseView; +#[doc(inline)] +pub use self::__buffa::view::IsBookInWishlistResponseOwnedView; +#[doc(inline)] +pub use self::__buffa::register_types; diff --git a/backend/src/proto/mod.rs b/backend/src/proto/mod.rs new file mode 100644 index 0000000..c23ac72 --- /dev/null +++ b/backend/src/proto/mod.rs @@ -0,0 +1,21 @@ +#[allow(dead_code, unused_imports, unused_qualifications)] +pub mod buf { + #[allow(dead_code, unused_imports, unused_qualifications)] + pub mod bookbridge { + #[allow(dead_code, unused_imports, unused_qualifications)] + pub mod v1 { + include!("buf/bookbridge.v1.rs"); + } + } +} + +#[allow(dead_code, unused_imports, unused_qualifications)] +pub mod svc { + #[allow(dead_code, unused_imports, unused_qualifications)] + pub mod bookbridge { + #[allow(dead_code, unused_imports, unused_qualifications)] + pub mod v1 { + include!("svc/bookbridge.v1.rs"); + } + } +} diff --git a/backend/src/proto/svc/bookbridge.v1.rs b/backend/src/proto/svc/bookbridge.v1.rs new file mode 100644 index 0000000..590db37 --- /dev/null +++ b/backend/src/proto/svc/bookbridge.v1.rs @@ -0,0 +1,12893 @@ +// @generated by connectrpc-codegen. DO NOT EDIT. + +///Shorthand for `OwnedView>`. +pub type OwnedSignUpRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignUpRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSignUpResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignUpResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSignInRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSignInResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSignInWithGoogleRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInWithGoogleRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSignInWithGoogleResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInWithGoogleResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedRefreshSessionRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RefreshSessionRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedRefreshSessionResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RefreshSessionResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSignOutRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignOutRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSignOutResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignOutResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetCurrentUserRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetCurrentUserRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetCurrentUserResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetCurrentUserResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedUpdateCurrentUserRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateCurrentUserRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedUpdateCurrentUserResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateCurrentUserResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSendPasswordResetRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendPasswordResetRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSendPasswordResetResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendPasswordResetResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSetDeviceTokenRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SetDeviceTokenRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSetDeviceTokenResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SetDeviceTokenResponseView<'static>, +>; +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::SignUpResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignUpResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::SignInResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::SignInWithGoogleResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInWithGoogleResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::RefreshSessionResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RefreshSessionResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::SignOutResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignOutResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::GetCurrentUserResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetCurrentUserResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::UpdateCurrentUserResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::UpdateCurrentUserResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::UpdateCurrentUserResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateCurrentUserResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SendPasswordResetResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::SendPasswordResetResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SendPasswordResetResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendPasswordResetResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::SetDeviceTokenResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SetDeviceTokenResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const AUTH_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.AuthService"; +/// Static [`Spec`](::connectrpc::Spec) for the `SignUp` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_SIGN_UP_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/SignUp", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `SignIn` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_SIGN_IN_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/SignIn", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `SignInWithGoogle` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_SIGN_IN_WITH_GOOGLE_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/SignInWithGoogle", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `RefreshSession` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_REFRESH_SESSION_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/RefreshSession", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `SignOut` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_SIGN_OUT_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/SignOut", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `GetCurrentUser` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_GET_CURRENT_USER_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/GetCurrentUser", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `UpdateCurrentUser` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_UPDATE_CURRENT_USER_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/UpdateCurrentUser", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `SendPasswordReset` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_SEND_PASSWORD_RESET_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/SendPasswordReset", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `SetDeviceToken` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const AUTH_SERVICE_SET_DEVICE_TOKEN_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.AuthService/SetDeviceToken", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for AuthService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait AuthService: Send + Sync + 'static { + /// Handle the SignUp RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn sign_up<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::SignUpRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SignUpResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the SignIn RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn sign_in<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::SignInRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SignInResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the SignInWithGoogle RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn sign_in_with_google<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::SignInWithGoogleRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SignInWithGoogleResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the RefreshSession RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn refresh_session<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::RefreshSessionRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::RefreshSessionResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the SignOut RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn sign_out<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::SignOutRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SignOutResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the GetCurrentUser RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_current_user<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetCurrentUserRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetCurrentUserResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the UpdateCurrentUser RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn update_current_user<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::UpdateCurrentUserRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::UpdateCurrentUserResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the SendPasswordReset RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn send_password_reset<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::SendPasswordResetRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SendPasswordResetResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the SetDeviceToken RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn set_device_token<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::SetDeviceTokenRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SetDeviceTokenResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait AuthServiceExt: AuthService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl AuthServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "SignUp", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignUpRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SignUpRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.sign_up(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SignUpResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_SIGN_UP_SPEC) + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "SignIn", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SignInRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.sign_in(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SignInResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_SIGN_IN_SPEC) + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "SignInWithGoogle", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInWithGoogleRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SignInWithGoogleRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.sign_in_with_google(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SignInWithGoogleResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_SIGN_IN_WITH_GOOGLE_SPEC) + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "RefreshSession", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RefreshSessionRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::RefreshSessionRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.refresh_session(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::RefreshSessionResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_REFRESH_SESSION_SPEC) + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "SignOut", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignOutRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SignOutRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.sign_out(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SignOutResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_SIGN_OUT_SPEC) + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "GetCurrentUser", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetCurrentUserRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetCurrentUserRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_current_user(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetCurrentUserResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_GET_CURRENT_USER_SPEC) + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "UpdateCurrentUser", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateCurrentUserRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::UpdateCurrentUserRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.update_current_user(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::UpdateCurrentUserResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_UPDATE_CURRENT_USER_SPEC) + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "SendPasswordReset", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendPasswordResetRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SendPasswordResetRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.send_password_reset(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SendPasswordResetResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_SEND_PASSWORD_RESET_SPEC) + .route_view( + AUTH_SERVICE_SERVICE_NAME, + "SetDeviceToken", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SetDeviceTokenRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SetDeviceTokenRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.set_device_token(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SetDeviceTokenResponse, + >(format) + } + }) + }, + ) + .with_spec(AUTH_SERVICE_SET_DEVICE_TOKEN_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct AuthServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `AuthService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = AuthServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct AuthServiceServer { + inner: ::std::sync::Arc, +} +impl AuthServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for AuthServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for AuthServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.AuthService/")?; + match method { + "SignUp" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_SIGN_UP_SPEC), + ) + } + "SignIn" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_SIGN_IN_SPEC), + ) + } + "SignInWithGoogle" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_SIGN_IN_WITH_GOOGLE_SPEC), + ) + } + "RefreshSession" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_REFRESH_SESSION_SPEC), + ) + } + "SignOut" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_SIGN_OUT_SPEC), + ) + } + "GetCurrentUser" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_GET_CURRENT_USER_SPEC), + ) + } + "UpdateCurrentUser" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_UPDATE_CURRENT_USER_SPEC), + ) + } + "SendPasswordReset" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_SEND_PASSWORD_RESET_SPEC), + ) + } + "SetDeviceToken" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(AUTH_SERVICE_SET_DEVICE_TOKEN_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.AuthService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "SignUp" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::SignUpRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::SignUpRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SignUpRequest, + >::from_parts(&req, &body); + svc.sign_up(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SignUpResponse, + >(format) + }) + } + "SignIn" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::SignInRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::SignInRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SignInRequest, + >::from_parts(&req, &body); + svc.sign_in(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SignInResponse, + >(format) + }) + } + "SignInWithGoogle" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::SignInWithGoogleRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::SignInWithGoogleRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SignInWithGoogleRequest, + >::from_parts(&req, &body); + svc.sign_in_with_google(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SignInWithGoogleResponse, + >(format) + }) + } + "RefreshSession" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::RefreshSessionRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::RefreshSessionRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::RefreshSessionRequest, + >::from_parts(&req, &body); + svc.refresh_session(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::RefreshSessionResponse, + >(format) + }) + } + "SignOut" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::SignOutRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::SignOutRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SignOutRequest, + >::from_parts(&req, &body); + svc.sign_out(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SignOutResponse, + >(format) + }) + } + "GetCurrentUser" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetCurrentUserRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetCurrentUserRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetCurrentUserRequest, + >::from_parts(&req, &body); + svc.get_current_user(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetCurrentUserResponse, + >(format) + }) + } + "UpdateCurrentUser" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::UpdateCurrentUserRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::UpdateCurrentUserRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::UpdateCurrentUserRequest, + >::from_parts(&req, &body); + svc.update_current_user(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::UpdateCurrentUserResponse, + >(format) + }) + } + "SendPasswordReset" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::SendPasswordResetRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::SendPasswordResetRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SendPasswordResetRequest, + >::from_parts(&req, &body); + svc.send_password_reset(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SendPasswordResetResponse, + >(format) + }) + } + "SetDeviceToken" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::SetDeviceTokenRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::SetDeviceTokenRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SetDeviceTokenRequest, + >::from_parts(&req, &body); + svc.set_device_token(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SetDeviceTokenResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.AuthService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.AuthService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.AuthService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = AuthServiceClient::new(conn, config); +/// let response = client.sign_up(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = AuthServiceClient::new(http, config); +/// let response = client.sign_up(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.sign_up(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.sign_up(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct AuthServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl AuthServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the SignUp RPC. Sends a request to /bookbridge.v1.AuthService/SignUp. + pub async fn sign_up( + &self, + request: crate::proto::buf::bookbridge::v1::SignUpRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignUpResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.sign_up_with_options(request, ::connectrpc::client::CallOptions::default()) + .await + } + /// Call the SignUp RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn sign_up_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::SignUpRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignUpResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_SIGN_UP_SPEC.with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the SignIn RPC. Sends a request to /bookbridge.v1.AuthService/SignIn. + pub async fn sign_in( + &self, + request: crate::proto::buf::bookbridge::v1::SignInRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.sign_in_with_options(request, ::connectrpc::client::CallOptions::default()) + .await + } + /// Call the SignIn RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn sign_in_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::SignInRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_SIGN_IN_SPEC.with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the SignInWithGoogle RPC. Sends a request to /bookbridge.v1.AuthService/SignInWithGoogle. + pub async fn sign_in_with_google( + &self, + request: crate::proto::buf::bookbridge::v1::SignInWithGoogleRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInWithGoogleResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.sign_in_with_google_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the SignInWithGoogle RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn sign_in_with_google_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::SignInWithGoogleRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignInWithGoogleResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_SIGN_IN_WITH_GOOGLE_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the RefreshSession RPC. Sends a request to /bookbridge.v1.AuthService/RefreshSession. + pub async fn refresh_session( + &self, + request: crate::proto::buf::bookbridge::v1::RefreshSessionRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RefreshSessionResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.refresh_session_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the RefreshSession RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn refresh_session_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::RefreshSessionRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RefreshSessionResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_REFRESH_SESSION_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the SignOut RPC. Sends a request to /bookbridge.v1.AuthService/SignOut. + pub async fn sign_out( + &self, + request: crate::proto::buf::bookbridge::v1::SignOutRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignOutResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.sign_out_with_options(request, ::connectrpc::client::CallOptions::default()) + .await + } + /// Call the SignOut RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn sign_out_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::SignOutRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SignOutResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_SIGN_OUT_SPEC.with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the GetCurrentUser RPC. Sends a request to /bookbridge.v1.AuthService/GetCurrentUser. + pub async fn get_current_user( + &self, + request: crate::proto::buf::bookbridge::v1::GetCurrentUserRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetCurrentUserResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_current_user_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the GetCurrentUser RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_current_user_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetCurrentUserRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetCurrentUserResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_GET_CURRENT_USER_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the UpdateCurrentUser RPC. Sends a request to /bookbridge.v1.AuthService/UpdateCurrentUser. + pub async fn update_current_user( + &self, + request: crate::proto::buf::bookbridge::v1::UpdateCurrentUserRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateCurrentUserResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.update_current_user_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the UpdateCurrentUser RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn update_current_user_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::UpdateCurrentUserRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateCurrentUserResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_UPDATE_CURRENT_USER_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the SendPasswordReset RPC. Sends a request to /bookbridge.v1.AuthService/SendPasswordReset. + pub async fn send_password_reset( + &self, + request: crate::proto::buf::bookbridge::v1::SendPasswordResetRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendPasswordResetResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.send_password_reset_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the SendPasswordReset RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn send_password_reset_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::SendPasswordResetRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendPasswordResetResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_SEND_PASSWORD_RESET_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the SetDeviceToken RPC. Sends a request to /bookbridge.v1.AuthService/SetDeviceToken. + pub async fn set_device_token( + &self, + request: crate::proto::buf::bookbridge::v1::SetDeviceTokenRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SetDeviceTokenResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.set_device_token_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the SetDeviceToken RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn set_device_token_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::SetDeviceTokenRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SetDeviceTokenResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + AUTH_SERVICE_SET_DEVICE_TOKEN_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedListCategoriesRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListCategoriesRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListCategoriesResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListCategoriesResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListBooksRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListBooksResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSearchBooksRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SearchBooksRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSearchBooksResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SearchBooksResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetBookRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBookRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetBookResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBookResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListBooksBySellerRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksBySellerRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListBooksBySellerResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksBySellerResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMyBooksRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyBooksRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMyBooksResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyBooksResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCreateBookRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCreateBookResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedUpdateBookRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateBookRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedUpdateBookResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateBookResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedDeleteBookRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteBookRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedDeleteBookResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteBookResponseView<'static>, +>; +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ListCategoriesResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListCategoriesResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::SearchBooksResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SearchBooksResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::GetBookResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBookResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListBooksBySellerResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksBySellerResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListBooksBySellerResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksBySellerResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ListMyBooksResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyBooksResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::UpdateBookResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateBookResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::DeleteBookResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteBookResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const BOOK_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.BookService"; +/// Static [`Spec`](::connectrpc::Spec) for the `ListCategories` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_LIST_CATEGORIES_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/ListCategories", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `ListBooks` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_LIST_BOOKS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/ListBooks", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `SearchBooks` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_SEARCH_BOOKS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/SearchBooks", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `GetBook` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_GET_BOOK_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/GetBook", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `ListBooksBySeller` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_LIST_BOOKS_BY_SELLER_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/ListBooksBySeller", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `ListMyBooks` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_LIST_MY_BOOKS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/ListMyBooks", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `CreateBook` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_CREATE_BOOK_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/CreateBook", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `UpdateBook` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_UPDATE_BOOK_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/UpdateBook", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `DeleteBook` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOK_SERVICE_DELETE_BOOK_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BookService/DeleteBook", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for BookService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait BookService: Send + Sync + 'static { + /// Handle the ListCategories RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_categories<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListCategoriesRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListCategoriesResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the ListBooks RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_books<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListBooksRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListBooksResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the SearchBooks RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn search_books<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::SearchBooksRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SearchBooksResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the GetBook RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_book<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetBookRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetBookResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the ListBooksBySeller RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_books_by_seller<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListBooksBySellerRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListBooksBySellerResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the ListMyBooks RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_my_books<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListMyBooksRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListMyBooksResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the CreateBook RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn create_book<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::CreateBookRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CreateBookResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the UpdateBook RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn update_book<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::UpdateBookRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::UpdateBookResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the DeleteBook RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn delete_book<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::DeleteBookRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::DeleteBookResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait BookServiceExt: BookService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl BookServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "ListCategories", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListCategoriesRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListCategoriesRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_categories(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListCategoriesResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_LIST_CATEGORIES_SPEC) + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "ListBooks", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListBooksRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_books(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListBooksResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_LIST_BOOKS_SPEC) + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "SearchBooks", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SearchBooksRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SearchBooksRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.search_books(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SearchBooksResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_SEARCH_BOOKS_SPEC) + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "GetBook", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBookRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetBookRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_book(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetBookResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_GET_BOOK_SPEC) + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "ListBooksBySeller", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksBySellerRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListBooksBySellerRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_books_by_seller(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListBooksBySellerResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_LIST_BOOKS_BY_SELLER_SPEC) + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "ListMyBooks", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyBooksRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMyBooksRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_my_books(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMyBooksResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_LIST_MY_BOOKS_SPEC) + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "CreateBook", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateBookRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.create_book(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateBookResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_CREATE_BOOK_SPEC) + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "UpdateBook", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateBookRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::UpdateBookRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.update_book(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::UpdateBookResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_UPDATE_BOOK_SPEC) + .route_view( + BOOK_SERVICE_SERVICE_NAME, + "DeleteBook", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteBookRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::DeleteBookRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.delete_book(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::DeleteBookResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOK_SERVICE_DELETE_BOOK_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct BookServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `BookService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = BookServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct BookServiceServer { + inner: ::std::sync::Arc, +} +impl BookServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for BookServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for BookServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.BookService/")?; + match method { + "ListCategories" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_LIST_CATEGORIES_SPEC), + ) + } + "ListBooks" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_LIST_BOOKS_SPEC), + ) + } + "SearchBooks" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_SEARCH_BOOKS_SPEC), + ) + } + "GetBook" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_GET_BOOK_SPEC), + ) + } + "ListBooksBySeller" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_LIST_BOOKS_BY_SELLER_SPEC), + ) + } + "ListMyBooks" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_LIST_MY_BOOKS_SPEC), + ) + } + "CreateBook" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_CREATE_BOOK_SPEC), + ) + } + "UpdateBook" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_UPDATE_BOOK_SPEC), + ) + } + "DeleteBook" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOK_SERVICE_DELETE_BOOK_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.BookService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "ListCategories" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListCategoriesRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListCategoriesRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListCategoriesRequest, + >::from_parts(&req, &body); + svc.list_categories(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListCategoriesResponse, + >(format) + }) + } + "ListBooks" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListBooksRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListBooksRequest, + >::from_parts(&req, &body); + svc.list_books(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListBooksResponse, + >(format) + }) + } + "SearchBooks" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::SearchBooksRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::SearchBooksRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SearchBooksRequest, + >::from_parts(&req, &body); + svc.search_books(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SearchBooksResponse, + >(format) + }) + } + "GetBook" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetBookRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetBookRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetBookRequest, + >::from_parts(&req, &body); + svc.get_book(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetBookResponse, + >(format) + }) + } + "ListBooksBySeller" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListBooksBySellerRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksBySellerRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListBooksBySellerRequest, + >::from_parts(&req, &body); + svc.list_books_by_seller(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListBooksBySellerResponse, + >(format) + }) + } + "ListMyBooks" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListMyBooksRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListMyBooksRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMyBooksRequest, + >::from_parts(&req, &body); + svc.list_my_books(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMyBooksResponse, + >(format) + }) + } + "CreateBook" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::CreateBookRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateBookRequest, + >::from_parts(&req, &body); + svc.create_book(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateBookResponse, + >(format) + }) + } + "UpdateBook" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::UpdateBookRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::UpdateBookRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::UpdateBookRequest, + >::from_parts(&req, &body); + svc.update_book(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::UpdateBookResponse, + >(format) + }) + } + "DeleteBook" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::DeleteBookRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::DeleteBookRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::DeleteBookRequest, + >::from_parts(&req, &body); + svc.delete_book(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::DeleteBookResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.BookService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.BookService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.BookService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = BookServiceClient::new(conn, config); +/// let response = client.list_categories(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = BookServiceClient::new(http, config); +/// let response = client.list_categories(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.list_categories(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.list_categories(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct BookServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl BookServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the ListCategories RPC. Sends a request to /bookbridge.v1.BookService/ListCategories. + pub async fn list_categories( + &self, + request: crate::proto::buf::bookbridge::v1::ListCategoriesRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListCategoriesResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_categories_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListCategories RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_categories_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListCategoriesRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListCategoriesResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_LIST_CATEGORIES_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the ListBooks RPC. Sends a request to /bookbridge.v1.BookService/ListBooks. + pub async fn list_books( + &self, + request: crate::proto::buf::bookbridge::v1::ListBooksRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_books_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListBooks RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_books_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListBooksRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_LIST_BOOKS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the SearchBooks RPC. Sends a request to /bookbridge.v1.BookService/SearchBooks. + pub async fn search_books( + &self, + request: crate::proto::buf::bookbridge::v1::SearchBooksRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SearchBooksResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.search_books_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the SearchBooks RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn search_books_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::SearchBooksRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SearchBooksResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_SEARCH_BOOKS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the GetBook RPC. Sends a request to /bookbridge.v1.BookService/GetBook. + pub async fn get_book( + &self, + request: crate::proto::buf::bookbridge::v1::GetBookRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBookResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_book_with_options(request, ::connectrpc::client::CallOptions::default()) + .await + } + /// Call the GetBook RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_book_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetBookRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBookResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_GET_BOOK_SPEC.with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the ListBooksBySeller RPC. Sends a request to /bookbridge.v1.BookService/ListBooksBySeller. + pub async fn list_books_by_seller( + &self, + request: crate::proto::buf::bookbridge::v1::ListBooksBySellerRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksBySellerResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_books_by_seller_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListBooksBySeller RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_books_by_seller_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListBooksBySellerRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListBooksBySellerResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_LIST_BOOKS_BY_SELLER_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the ListMyBooks RPC. Sends a request to /bookbridge.v1.BookService/ListMyBooks. + pub async fn list_my_books( + &self, + request: crate::proto::buf::bookbridge::v1::ListMyBooksRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyBooksResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_my_books_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListMyBooks RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_my_books_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListMyBooksRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyBooksResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_LIST_MY_BOOKS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the CreateBook RPC. Sends a request to /bookbridge.v1.BookService/CreateBook. + pub async fn create_book( + &self, + request: crate::proto::buf::bookbridge::v1::CreateBookRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.create_book_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the CreateBook RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn create_book_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::CreateBookRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_CREATE_BOOK_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the UpdateBook RPC. Sends a request to /bookbridge.v1.BookService/UpdateBook. + pub async fn update_book( + &self, + request: crate::proto::buf::bookbridge::v1::UpdateBookRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateBookResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.update_book_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the UpdateBook RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn update_book_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::UpdateBookRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::UpdateBookResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_UPDATE_BOOK_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the DeleteBook RPC. Sends a request to /bookbridge.v1.BookService/DeleteBook. + pub async fn delete_book( + &self, + request: crate::proto::buf::bookbridge::v1::DeleteBookRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteBookResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.delete_book_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the DeleteBook RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn delete_book_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::DeleteBookRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteBookResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOK_SERVICE_DELETE_BOOK_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedCreateBoostRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBoostRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCreateBoostResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBoostResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetBoostStatusRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBoostStatusRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetBoostStatusResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBoostStatusResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCreateDonationRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateDonationRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCreateDonationResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateDonationResponseView<'static>, +>; +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::CreateBoostResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBoostResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::GetBoostStatusResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBoostStatusResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::CreateDonationResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateDonationResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const BOOST_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.BoostService"; +/// Static [`Spec`](::connectrpc::Spec) for the `CreateBoost` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOST_SERVICE_CREATE_BOOST_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BoostService/CreateBoost", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `GetBoostStatus` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const BOOST_SERVICE_GET_BOOST_STATUS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.BoostService/GetBoostStatus", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for BoostService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait BoostService: Send + Sync + 'static { + /// Handle the CreateBoost RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn create_boost<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::CreateBoostRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CreateBoostResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the GetBoostStatus RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_boost_status<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetBoostStatusRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetBoostStatusResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait BoostServiceExt: BoostService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl BoostServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + BOOST_SERVICE_SERVICE_NAME, + "CreateBoost", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBoostRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateBoostRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.create_boost(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateBoostResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOST_SERVICE_CREATE_BOOST_SPEC) + .route_view( + BOOST_SERVICE_SERVICE_NAME, + "GetBoostStatus", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBoostStatusRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetBoostStatusRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_boost_status(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetBoostStatusResponse, + >(format) + } + }) + }, + ) + .with_spec(BOOST_SERVICE_GET_BOOST_STATUS_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct BoostServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `BoostService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = BoostServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct BoostServiceServer { + inner: ::std::sync::Arc, +} +impl BoostServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for BoostServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for BoostServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.BoostService/")?; + match method { + "CreateBoost" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOST_SERVICE_CREATE_BOOST_SPEC), + ) + } + "GetBoostStatus" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(BOOST_SERVICE_GET_BOOST_STATUS_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.BoostService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "CreateBoost" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::CreateBoostRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::CreateBoostRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateBoostRequest, + >::from_parts(&req, &body); + svc.create_boost(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateBoostResponse, + >(format) + }) + } + "GetBoostStatus" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetBoostStatusRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetBoostStatusRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetBoostStatusRequest, + >::from_parts(&req, &body); + svc.get_boost_status(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetBoostStatusResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.BoostService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.BoostService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.BoostService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = BoostServiceClient::new(conn, config); +/// let response = client.create_boost(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = BoostServiceClient::new(http, config); +/// let response = client.create_boost(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.create_boost(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.create_boost(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct BoostServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl BoostServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the CreateBoost RPC. Sends a request to /bookbridge.v1.BoostService/CreateBoost. + pub async fn create_boost( + &self, + request: crate::proto::buf::bookbridge::v1::CreateBoostRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBoostResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.create_boost_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the CreateBoost RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn create_boost_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::CreateBoostRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBoostResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOST_SERVICE_CREATE_BOOST_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the GetBoostStatus RPC. Sends a request to /bookbridge.v1.BoostService/GetBoostStatus. + pub async fn get_boost_status( + &self, + request: crate::proto::buf::bookbridge::v1::GetBoostStatusRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBoostStatusResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_boost_status_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the GetBoostStatus RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_boost_status_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetBoostStatusRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetBoostStatusResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + BOOST_SERVICE_GET_BOOST_STATUS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} +/// Full service name for this service. +pub const DONATION_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.DonationService"; +/// Static [`Spec`](::connectrpc::Spec) for the `CreateDonation` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const DONATION_SERVICE_CREATE_DONATION_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.DonationService/CreateDonation", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for DonationService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait DonationService: Send + Sync + 'static { + /// Handle the CreateDonation RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn create_donation<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::CreateDonationRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CreateDonationResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait DonationServiceExt: DonationService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl DonationServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + DONATION_SERVICE_SERVICE_NAME, + "CreateDonation", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateDonationRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateDonationRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.create_donation(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateDonationResponse, + >(format) + } + }) + }, + ) + .with_spec(DONATION_SERVICE_CREATE_DONATION_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct DonationServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `DonationService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = DonationServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct DonationServiceServer { + inner: ::std::sync::Arc, +} +impl DonationServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for DonationServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for DonationServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.DonationService/")?; + match method { + "CreateDonation" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(DONATION_SERVICE_CREATE_DONATION_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.DonationService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "CreateDonation" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::CreateDonationRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::CreateDonationRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateDonationRequest, + >::from_parts(&req, &body); + svc.create_donation(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateDonationResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.DonationService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.DonationService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.DonationService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = DonationServiceClient::new(conn, config); +/// let response = client.create_donation(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = DonationServiceClient::new(http, config); +/// let response = client.create_donation(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.create_donation(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.create_donation(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct DonationServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl DonationServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the CreateDonation RPC. Sends a request to /bookbridge.v1.DonationService/CreateDonation. + pub async fn create_donation( + &self, + request: crate::proto::buf::bookbridge::v1::CreateDonationRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateDonationResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.create_donation_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the CreateDonation RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn create_donation_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::CreateDonationRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateDonationResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + DONATION_SERVICE_CREATE_DONATION_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedListConversationsRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListConversationsRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListConversationsResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListConversationsResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetOrCreateConversationRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetOrCreateConversationRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetOrCreateConversationResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetOrCreateConversationResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMessagesRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMessagesRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMessagesResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMessagesResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSendMessageRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendMessageRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedSendMessageResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendMessageResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedMarkMessagesReadRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkMessagesReadRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedMarkMessagesReadResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkMessagesReadResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedStreamConversationsRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::StreamConversationsRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedStreamConversationsResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::StreamConversationsResponseView< + 'static, + >, +>; +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListConversationsResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::ListConversationsResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListConversationsResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListConversationsResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetOrCreateConversationResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::GetOrCreateConversationResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetOrCreateConversationResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetOrCreateConversationResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ListMessagesResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMessagesResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::SendMessageResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendMessageResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::MarkMessagesReadResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkMessagesReadResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::StreamConversationsResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::StreamConversationsResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::StreamConversationsResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::StreamConversationsResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const CHAT_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.ChatService"; +/// Static [`Spec`](::connectrpc::Spec) for the `ListConversations` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const CHAT_SERVICE_LIST_CONVERSATIONS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ChatService/ListConversations", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `GetOrCreateConversation` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const CHAT_SERVICE_GET_OR_CREATE_CONVERSATION_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ChatService/GetOrCreateConversation", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `ListMessages` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const CHAT_SERVICE_LIST_MESSAGES_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ChatService/ListMessages", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `SendMessage` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const CHAT_SERVICE_SEND_MESSAGE_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ChatService/SendMessage", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `MarkMessagesRead` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const CHAT_SERVICE_MARK_MESSAGES_READ_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ChatService/MarkMessagesRead", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `StreamConversations` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const CHAT_SERVICE_STREAM_CONVERSATIONS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ChatService/StreamConversations", + ::connectrpc::StreamType::ServerStream, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for ChatService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait ChatService: Send + Sync + 'static { + /// Handle the ListConversations RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_conversations<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListConversationsRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListConversationsResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the GetOrCreateConversation RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_or_create_conversation<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetOrCreateConversationRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetOrCreateConversationResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the ListMessages RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_messages<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListMessagesRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListMessagesResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the SendMessage RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn send_message<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::SendMessageRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::SendMessageResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the MarkMessagesRead RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn mark_messages_read<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::MarkMessagesReadRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::MarkMessagesReadResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the StreamConversations RPC. + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call (until the response stream is returned); + /// message fields are read directly on it (zero-copy). Data the + /// returned stream needs must be copied out or converted via + /// `.to_owned_message()`. + fn stream_conversations( + &self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::StreamConversationsRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + ::connectrpc::ServiceStream< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::StreamConversationsResponse, + > + Send + use, + >, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait ChatServiceExt: ChatService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl ChatServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + CHAT_SERVICE_SERVICE_NAME, + "ListConversations", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListConversationsRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListConversationsRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_conversations(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListConversationsResponse, + >(format) + } + }) + }, + ) + .with_spec(CHAT_SERVICE_LIST_CONVERSATIONS_SPEC) + .route_view( + CHAT_SERVICE_SERVICE_NAME, + "GetOrCreateConversation", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetOrCreateConversationRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetOrCreateConversationRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_or_create_conversation(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetOrCreateConversationResponse, + >(format) + } + }) + }, + ) + .with_spec(CHAT_SERVICE_GET_OR_CREATE_CONVERSATION_SPEC) + .route_view( + CHAT_SERVICE_SERVICE_NAME, + "ListMessages", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMessagesRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMessagesRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_messages(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMessagesResponse, + >(format) + } + }) + }, + ) + .with_spec(CHAT_SERVICE_LIST_MESSAGES_SPEC) + .route_view( + CHAT_SERVICE_SERVICE_NAME, + "SendMessage", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendMessageRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SendMessageRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.send_message(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SendMessageResponse, + >(format) + } + }) + }, + ) + .with_spec(CHAT_SERVICE_SEND_MESSAGE_SPEC) + .route_view( + CHAT_SERVICE_SERVICE_NAME, + "MarkMessagesRead", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkMessagesReadRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::MarkMessagesReadRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.mark_messages_read(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::MarkMessagesReadResponse, + >(format) + } + }) + }, + ) + .with_spec(CHAT_SERVICE_MARK_MESSAGES_READ_SPEC) + .route_view_server_stream::< + _, + _, + crate::proto::buf::bookbridge::v1::StreamConversationsResponse, + >( + CHAT_SERVICE_SERVICE_NAME, + "StreamConversations", + ::connectrpc::view_streaming_handler_fn({ + let svc = ::std::sync::Arc::clone(&self); + move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::StreamConversationsRequestView< + 'static, + >, + >| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::StreamConversationsRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.stream_conversations(ctx, sreq).await + } + } + }), + ) + .with_spec(CHAT_SERVICE_STREAM_CONVERSATIONS_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct ChatServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `ChatService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = ChatServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct ChatServiceServer { + inner: ::std::sync::Arc, +} +impl ChatServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for ChatServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for ChatServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.ChatService/")?; + match method { + "ListConversations" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(CHAT_SERVICE_LIST_CONVERSATIONS_SPEC), + ) + } + "GetOrCreateConversation" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(CHAT_SERVICE_GET_OR_CREATE_CONVERSATION_SPEC), + ) + } + "ListMessages" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(CHAT_SERVICE_LIST_MESSAGES_SPEC), + ) + } + "SendMessage" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(CHAT_SERVICE_SEND_MESSAGE_SPEC), + ) + } + "MarkMessagesRead" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(CHAT_SERVICE_MARK_MESSAGES_READ_SPEC), + ) + } + "StreamConversations" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::server_streaming() + .with_spec(CHAT_SERVICE_STREAM_CONVERSATIONS_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.ChatService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "ListConversations" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListConversationsRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListConversationsRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListConversationsRequest, + >::from_parts(&req, &body); + svc.list_conversations(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListConversationsResponse, + >(format) + }) + } + "GetOrCreateConversation" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetOrCreateConversationRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetOrCreateConversationRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetOrCreateConversationRequest, + >::from_parts(&req, &body); + svc.get_or_create_conversation(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetOrCreateConversationResponse, + >(format) + }) + } + "ListMessages" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListMessagesRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListMessagesRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMessagesRequest, + >::from_parts(&req, &body); + svc.list_messages(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMessagesResponse, + >(format) + }) + } + "SendMessage" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::SendMessageRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::SendMessageRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::SendMessageRequest, + >::from_parts(&req, &body); + svc.send_message(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::SendMessageResponse, + >(format) + }) + } + "MarkMessagesRead" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::MarkMessagesReadRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::MarkMessagesReadRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::MarkMessagesReadRequest, + >::from_parts(&req, &body); + svc.mark_messages_read(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::MarkMessagesReadResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.ChatService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + "StreamConversations" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::StreamConversationsRequest, + >(request, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::StreamConversationsRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::StreamConversationsRequest, + >::from_parts(&req, &body); + let resp = svc.stream_conversations(ctx, req).await?; + Ok( + resp + .map_body(|s| ::connectrpc::dispatcher::codegen::encode_response_stream::< + crate::proto::buf::bookbridge::v1::StreamConversationsResponse, + _, + _, + >(s, format)), + ) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.ChatService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.ChatService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = ChatServiceClient::new(conn, config); +/// let response = client.list_conversations(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = ChatServiceClient::new(http, config); +/// let response = client.list_conversations(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.list_conversations(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.list_conversations(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct ChatServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl ChatServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the ListConversations RPC. Sends a request to /bookbridge.v1.ChatService/ListConversations. + pub async fn list_conversations( + &self, + request: crate::proto::buf::bookbridge::v1::ListConversationsRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListConversationsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_conversations_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListConversations RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_conversations_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListConversationsRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListConversationsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + CHAT_SERVICE_LIST_CONVERSATIONS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the GetOrCreateConversation RPC. Sends a request to /bookbridge.v1.ChatService/GetOrCreateConversation. + pub async fn get_or_create_conversation( + &self, + request: crate::proto::buf::bookbridge::v1::GetOrCreateConversationRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetOrCreateConversationResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_or_create_conversation_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the GetOrCreateConversation RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_or_create_conversation_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetOrCreateConversationRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetOrCreateConversationResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + CHAT_SERVICE_GET_OR_CREATE_CONVERSATION_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the ListMessages RPC. Sends a request to /bookbridge.v1.ChatService/ListMessages. + pub async fn list_messages( + &self, + request: crate::proto::buf::bookbridge::v1::ListMessagesRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMessagesResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_messages_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListMessages RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_messages_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListMessagesRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMessagesResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + CHAT_SERVICE_LIST_MESSAGES_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the SendMessage RPC. Sends a request to /bookbridge.v1.ChatService/SendMessage. + pub async fn send_message( + &self, + request: crate::proto::buf::bookbridge::v1::SendMessageRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendMessageResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.send_message_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the SendMessage RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn send_message_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::SendMessageRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::SendMessageResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + CHAT_SERVICE_SEND_MESSAGE_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the MarkMessagesRead RPC. Sends a request to /bookbridge.v1.ChatService/MarkMessagesRead. + pub async fn mark_messages_read( + &self, + request: crate::proto::buf::bookbridge::v1::MarkMessagesReadRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkMessagesReadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.mark_messages_read_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the MarkMessagesRead RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn mark_messages_read_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::MarkMessagesReadRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkMessagesReadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + CHAT_SERVICE_MARK_MESSAGES_READ_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the StreamConversations RPC. Sends a request to /bookbridge.v1.ChatService/StreamConversations. + pub async fn stream_conversations( + &self, + request: crate::proto::buf::bookbridge::v1::StreamConversationsRequest, + ) -> Result< + ::connectrpc::client::ServerStream< + T::ResponseBody, + crate::proto::buf::bookbridge::v1::__buffa::view::StreamConversationsResponseView< + 'static, + >, + >, + ::connectrpc::ConnectError, + > { + self.stream_conversations_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the StreamConversations RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn stream_conversations_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::StreamConversationsRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::ServerStream< + T::ResponseBody, + crate::proto::buf::bookbridge::v1::__buffa::view::StreamConversationsResponseView< + 'static, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_server_stream( + &self.transport, + &self.config, + CHAT_SERVICE_STREAM_CONVERSATIONS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedListMeetupLocationsRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMeetupLocationsRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMeetupLocationsResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMeetupLocationsResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetMeetupLocationRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetMeetupLocationRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetMeetupLocationResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetMeetupLocationResponseView< + 'static, + >, +>; +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListMeetupLocationsResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::ListMeetupLocationsResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListMeetupLocationsResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMeetupLocationsResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetMeetupLocationResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::GetMeetupLocationResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetMeetupLocationResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetMeetupLocationResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const MEETUP_LOCATION_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.MeetupLocationService"; +/// Static [`Spec`](::connectrpc::Spec) for the `ListMeetupLocations` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const MEETUP_LOCATION_SERVICE_LIST_MEETUP_LOCATIONS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.MeetupLocationService/ListMeetupLocations", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `GetMeetupLocation` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const MEETUP_LOCATION_SERVICE_GET_MEETUP_LOCATION_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.MeetupLocationService/GetMeetupLocation", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for MeetupLocationService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait MeetupLocationService: Send + Sync + 'static { + /// Handle the ListMeetupLocations RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_meetup_locations<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListMeetupLocationsRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListMeetupLocationsResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the GetMeetupLocation RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_meetup_location<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetMeetupLocationRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetMeetupLocationResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait MeetupLocationServiceExt: MeetupLocationService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl MeetupLocationServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + MEETUP_LOCATION_SERVICE_SERVICE_NAME, + "ListMeetupLocations", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMeetupLocationsRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMeetupLocationsRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_meetup_locations(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMeetupLocationsResponse, + >(format) + } + }) + }, + ) + .with_spec(MEETUP_LOCATION_SERVICE_LIST_MEETUP_LOCATIONS_SPEC) + .route_view( + MEETUP_LOCATION_SERVICE_SERVICE_NAME, + "GetMeetupLocation", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetMeetupLocationRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetMeetupLocationRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_meetup_location(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetMeetupLocationResponse, + >(format) + } + }) + }, + ) + .with_spec(MEETUP_LOCATION_SERVICE_GET_MEETUP_LOCATION_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct MeetupLocationServiceRegisterMarker; +impl< + S: MeetupLocationService, +> ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `MeetupLocationService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = MeetupLocationServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct MeetupLocationServiceServer { + inner: ::std::sync::Arc, +} +impl MeetupLocationServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for MeetupLocationServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher +for MeetupLocationServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.MeetupLocationService/")?; + match method { + "ListMeetupLocations" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(MEETUP_LOCATION_SERVICE_LIST_MEETUP_LOCATIONS_SPEC), + ) + } + "GetMeetupLocation" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(MEETUP_LOCATION_SERVICE_GET_MEETUP_LOCATION_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.MeetupLocationService/") + else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "ListMeetupLocations" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListMeetupLocationsRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListMeetupLocationsRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMeetupLocationsRequest, + >::from_parts(&req, &body); + svc.list_meetup_locations(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMeetupLocationsResponse, + >(format) + }) + } + "GetMeetupLocation" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetMeetupLocationRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetMeetupLocationRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetMeetupLocationRequest, + >::from_parts(&req, &body); + svc.get_meetup_location(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetMeetupLocationResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.MeetupLocationService/") + else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.MeetupLocationService/") + else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.MeetupLocationService/") + else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = MeetupLocationServiceClient::new(conn, config); +/// let response = client.list_meetup_locations(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = MeetupLocationServiceClient::new(http, config); +/// let response = client.list_meetup_locations(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.list_meetup_locations(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.list_meetup_locations(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct MeetupLocationServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl MeetupLocationServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the ListMeetupLocations RPC. Sends a request to /bookbridge.v1.MeetupLocationService/ListMeetupLocations. + pub async fn list_meetup_locations( + &self, + request: crate::proto::buf::bookbridge::v1::ListMeetupLocationsRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMeetupLocationsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_meetup_locations_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListMeetupLocations RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_meetup_locations_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListMeetupLocationsRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMeetupLocationsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + MEETUP_LOCATION_SERVICE_LIST_MEETUP_LOCATIONS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the GetMeetupLocation RPC. Sends a request to /bookbridge.v1.MeetupLocationService/GetMeetupLocation. + pub async fn get_meetup_location( + &self, + request: crate::proto::buf::bookbridge::v1::GetMeetupLocationRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetMeetupLocationResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_meetup_location_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the GetMeetupLocation RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_meetup_location_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetMeetupLocationRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetMeetupLocationResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + MEETUP_LOCATION_SERVICE_GET_MEETUP_LOCATION_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedListNotificationsRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListNotificationsRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListNotificationsResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListNotificationsResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedMarkNotificationReadRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkNotificationReadRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedMarkNotificationReadResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkNotificationReadResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedMarkAllNotificationsReadRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkAllNotificationsReadRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedMarkAllNotificationsReadResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkAllNotificationsReadResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedStreamNotificationsRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::StreamNotificationsRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedStreamNotificationsResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::StreamNotificationsResponseView< + 'static, + >, +>; +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListNotificationsResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::ListNotificationsResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListNotificationsResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListNotificationsResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::MarkNotificationReadResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::MarkNotificationReadResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::MarkNotificationReadResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkNotificationReadResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::MarkAllNotificationsReadResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkAllNotificationsReadResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::StreamNotificationsResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::StreamNotificationsResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::StreamNotificationsResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::StreamNotificationsResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const NOTIFICATION_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.NotificationService"; +/// Static [`Spec`](::connectrpc::Spec) for the `ListNotifications` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const NOTIFICATION_SERVICE_LIST_NOTIFICATIONS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.NotificationService/ListNotifications", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `MarkNotificationRead` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const NOTIFICATION_SERVICE_MARK_NOTIFICATION_READ_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.NotificationService/MarkNotificationRead", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `MarkAllNotificationsRead` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const NOTIFICATION_SERVICE_MARK_ALL_NOTIFICATIONS_READ_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.NotificationService/MarkAllNotificationsRead", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `StreamNotifications` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const NOTIFICATION_SERVICE_STREAM_NOTIFICATIONS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.NotificationService/StreamNotifications", + ::connectrpc::StreamType::ServerStream, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for NotificationService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait NotificationService: Send + Sync + 'static { + /// Handle the ListNotifications RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_notifications<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListNotificationsRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListNotificationsResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the MarkNotificationRead RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn mark_notification_read<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::MarkNotificationReadRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::MarkNotificationReadResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the MarkAllNotificationsRead RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn mark_all_notifications_read<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the StreamNotifications RPC. + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call (until the response stream is returned); + /// message fields are read directly on it (zero-copy). Data the + /// returned stream needs must be copied out or converted via + /// `.to_owned_message()`. + fn stream_notifications( + &self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::StreamNotificationsRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + ::connectrpc::ServiceStream< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::StreamNotificationsResponse, + > + Send + use, + >, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait NotificationServiceExt: NotificationService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl NotificationServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + NOTIFICATION_SERVICE_SERVICE_NAME, + "ListNotifications", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListNotificationsRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListNotificationsRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_notifications(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListNotificationsResponse, + >(format) + } + }) + }, + ) + .with_spec(NOTIFICATION_SERVICE_LIST_NOTIFICATIONS_SPEC) + .route_view( + NOTIFICATION_SERVICE_SERVICE_NAME, + "MarkNotificationRead", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkNotificationReadRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::MarkNotificationReadRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.mark_notification_read(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::MarkNotificationReadResponse, + >(format) + } + }) + }, + ) + .with_spec(NOTIFICATION_SERVICE_MARK_NOTIFICATION_READ_SPEC) + .route_view( + NOTIFICATION_SERVICE_SERVICE_NAME, + "MarkAllNotificationsRead", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkAllNotificationsReadRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.mark_all_notifications_read(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadResponse, + >(format) + } + }) + }, + ) + .with_spec(NOTIFICATION_SERVICE_MARK_ALL_NOTIFICATIONS_READ_SPEC) + .route_view_server_stream::< + _, + _, + crate::proto::buf::bookbridge::v1::StreamNotificationsResponse, + >( + NOTIFICATION_SERVICE_SERVICE_NAME, + "StreamNotifications", + ::connectrpc::view_streaming_handler_fn({ + let svc = ::std::sync::Arc::clone(&self); + move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::StreamNotificationsRequestView< + 'static, + >, + >| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::StreamNotificationsRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.stream_notifications(ctx, sreq).await + } + } + }), + ) + .with_spec(NOTIFICATION_SERVICE_STREAM_NOTIFICATIONS_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct NotificationServiceRegisterMarker; +impl< + S: NotificationService, +> ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `NotificationService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = NotificationServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct NotificationServiceServer { + inner: ::std::sync::Arc, +} +impl NotificationServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for NotificationServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for NotificationServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.NotificationService/")?; + match method { + "ListNotifications" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(NOTIFICATION_SERVICE_LIST_NOTIFICATIONS_SPEC), + ) + } + "MarkNotificationRead" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(NOTIFICATION_SERVICE_MARK_NOTIFICATION_READ_SPEC), + ) + } + "MarkAllNotificationsRead" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(NOTIFICATION_SERVICE_MARK_ALL_NOTIFICATIONS_READ_SPEC), + ) + } + "StreamNotifications" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::server_streaming() + .with_spec(NOTIFICATION_SERVICE_STREAM_NOTIFICATIONS_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.NotificationService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "ListNotifications" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListNotificationsRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListNotificationsRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListNotificationsRequest, + >::from_parts(&req, &body); + svc.list_notifications(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListNotificationsResponse, + >(format) + }) + } + "MarkNotificationRead" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::MarkNotificationReadRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::MarkNotificationReadRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::MarkNotificationReadRequest, + >::from_parts(&req, &body); + svc.mark_notification_read(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::MarkNotificationReadResponse, + >(format) + }) + } + "MarkAllNotificationsRead" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::MarkAllNotificationsReadRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadRequest, + >::from_parts(&req, &body); + svc.mark_all_notifications_read(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.NotificationService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + "StreamNotifications" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::StreamNotificationsRequest, + >(request, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::StreamNotificationsRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::StreamNotificationsRequest, + >::from_parts(&req, &body); + let resp = svc.stream_notifications(ctx, req).await?; + Ok( + resp + .map_body(|s| ::connectrpc::dispatcher::codegen::encode_response_stream::< + crate::proto::buf::bookbridge::v1::StreamNotificationsResponse, + _, + _, + >(s, format)), + ) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.NotificationService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.NotificationService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = NotificationServiceClient::new(conn, config); +/// let response = client.list_notifications(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = NotificationServiceClient::new(http, config); +/// let response = client.list_notifications(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.list_notifications(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.list_notifications(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct NotificationServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl NotificationServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the ListNotifications RPC. Sends a request to /bookbridge.v1.NotificationService/ListNotifications. + pub async fn list_notifications( + &self, + request: crate::proto::buf::bookbridge::v1::ListNotificationsRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListNotificationsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_notifications_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListNotifications RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_notifications_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListNotificationsRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListNotificationsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + NOTIFICATION_SERVICE_LIST_NOTIFICATIONS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the MarkNotificationRead RPC. Sends a request to /bookbridge.v1.NotificationService/MarkNotificationRead. + pub async fn mark_notification_read( + &self, + request: crate::proto::buf::bookbridge::v1::MarkNotificationReadRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkNotificationReadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.mark_notification_read_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the MarkNotificationRead RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn mark_notification_read_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::MarkNotificationReadRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkNotificationReadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + NOTIFICATION_SERVICE_MARK_NOTIFICATION_READ_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the MarkAllNotificationsRead RPC. Sends a request to /bookbridge.v1.NotificationService/MarkAllNotificationsRead. + pub async fn mark_all_notifications_read( + &self, + request: crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkAllNotificationsReadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.mark_all_notifications_read_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the MarkAllNotificationsRead RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn mark_all_notifications_read_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::MarkAllNotificationsReadRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::MarkAllNotificationsReadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + NOTIFICATION_SERVICE_MARK_ALL_NOTIFICATIONS_READ_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the StreamNotifications RPC. Sends a request to /bookbridge.v1.NotificationService/StreamNotifications. + pub async fn stream_notifications( + &self, + request: crate::proto::buf::bookbridge::v1::StreamNotificationsRequest, + ) -> Result< + ::connectrpc::client::ServerStream< + T::ResponseBody, + crate::proto::buf::bookbridge::v1::__buffa::view::StreamNotificationsResponseView< + 'static, + >, + >, + ::connectrpc::ConnectError, + > { + self.stream_notifications_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the StreamNotifications RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn stream_notifications_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::StreamNotificationsRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::ServerStream< + T::ResponseBody, + crate::proto::buf::bookbridge::v1::__buffa::view::StreamNotificationsResponseView< + 'static, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_server_stream( + &self.transport, + &self.config, + NOTIFICATION_SERVICE_STREAM_NOTIFICATIONS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedCreateBookPurchaseRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookPurchaseRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCreateBookPurchaseResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookPurchaseResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetPurchaseRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPurchaseRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetPurchaseResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPurchaseResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMyPurchasesRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyPurchasesRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMyPurchasesResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyPurchasesResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMySalesRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMySalesRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListMySalesResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMySalesResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedConfirmReceiptRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ConfirmReceiptRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedConfirmReceiptResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ConfirmReceiptResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedDisputePurchaseRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DisputePurchaseRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedDisputePurchaseResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DisputePurchaseResponseView< + 'static, + >, +>; +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CreateBookPurchaseResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookPurchaseResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CreateBookPurchaseResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookPurchaseResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::GetPurchaseResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPurchaseResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ListMyPurchasesResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyPurchasesResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ListMySalesResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMySalesResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ConfirmReceiptResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ConfirmReceiptResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::DisputePurchaseResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DisputePurchaseResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const PURCHASE_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.PurchaseService"; +/// Static [`Spec`](::connectrpc::Spec) for the `CreateBookPurchase` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const PURCHASE_SERVICE_CREATE_BOOK_PURCHASE_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.PurchaseService/CreateBookPurchase", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `GetPurchase` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const PURCHASE_SERVICE_GET_PURCHASE_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.PurchaseService/GetPurchase", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `ListMyPurchases` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const PURCHASE_SERVICE_LIST_MY_PURCHASES_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.PurchaseService/ListMyPurchases", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `ListMySales` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const PURCHASE_SERVICE_LIST_MY_SALES_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.PurchaseService/ListMySales", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `ConfirmReceipt` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const PURCHASE_SERVICE_CONFIRM_RECEIPT_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.PurchaseService/ConfirmReceipt", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `DisputePurchase` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const PURCHASE_SERVICE_DISPUTE_PURCHASE_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.PurchaseService/DisputePurchase", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for PurchaseService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait PurchaseService: Send + Sync + 'static { + /// Handle the CreateBookPurchase RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn create_book_purchase<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::CreateBookPurchaseRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CreateBookPurchaseResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the GetPurchase RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_purchase<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetPurchaseRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetPurchaseResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the ListMyPurchases RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_my_purchases<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListMyPurchasesRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListMyPurchasesResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the ListMySales RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_my_sales<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListMySalesRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListMySalesResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the ConfirmReceipt RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn confirm_receipt<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ConfirmReceiptRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ConfirmReceiptResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the DisputePurchase RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn dispute_purchase<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::DisputePurchaseRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::DisputePurchaseResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait PurchaseServiceExt: PurchaseService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl PurchaseServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + PURCHASE_SERVICE_SERVICE_NAME, + "CreateBookPurchase", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookPurchaseRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateBookPurchaseRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.create_book_purchase(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateBookPurchaseResponse, + >(format) + } + }) + }, + ) + .with_spec(PURCHASE_SERVICE_CREATE_BOOK_PURCHASE_SPEC) + .route_view( + PURCHASE_SERVICE_SERVICE_NAME, + "GetPurchase", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPurchaseRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetPurchaseRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_purchase(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetPurchaseResponse, + >(format) + } + }) + }, + ) + .with_spec(PURCHASE_SERVICE_GET_PURCHASE_SPEC) + .route_view( + PURCHASE_SERVICE_SERVICE_NAME, + "ListMyPurchases", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyPurchasesRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMyPurchasesRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_my_purchases(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMyPurchasesResponse, + >(format) + } + }) + }, + ) + .with_spec(PURCHASE_SERVICE_LIST_MY_PURCHASES_SPEC) + .route_view( + PURCHASE_SERVICE_SERVICE_NAME, + "ListMySales", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMySalesRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMySalesRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_my_sales(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMySalesResponse, + >(format) + } + }) + }, + ) + .with_spec(PURCHASE_SERVICE_LIST_MY_SALES_SPEC) + .route_view( + PURCHASE_SERVICE_SERVICE_NAME, + "ConfirmReceipt", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ConfirmReceiptRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ConfirmReceiptRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.confirm_receipt(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ConfirmReceiptResponse, + >(format) + } + }) + }, + ) + .with_spec(PURCHASE_SERVICE_CONFIRM_RECEIPT_SPEC) + .route_view( + PURCHASE_SERVICE_SERVICE_NAME, + "DisputePurchase", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DisputePurchaseRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::DisputePurchaseRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.dispute_purchase(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::DisputePurchaseResponse, + >(format) + } + }) + }, + ) + .with_spec(PURCHASE_SERVICE_DISPUTE_PURCHASE_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct PurchaseServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `PurchaseService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = PurchaseServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct PurchaseServiceServer { + inner: ::std::sync::Arc, +} +impl PurchaseServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for PurchaseServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for PurchaseServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.PurchaseService/")?; + match method { + "CreateBookPurchase" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(PURCHASE_SERVICE_CREATE_BOOK_PURCHASE_SPEC), + ) + } + "GetPurchase" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(PURCHASE_SERVICE_GET_PURCHASE_SPEC), + ) + } + "ListMyPurchases" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(PURCHASE_SERVICE_LIST_MY_PURCHASES_SPEC), + ) + } + "ListMySales" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(PURCHASE_SERVICE_LIST_MY_SALES_SPEC), + ) + } + "ConfirmReceipt" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(PURCHASE_SERVICE_CONFIRM_RECEIPT_SPEC), + ) + } + "DisputePurchase" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(PURCHASE_SERVICE_DISPUTE_PURCHASE_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.PurchaseService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "CreateBookPurchase" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::CreateBookPurchaseRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookPurchaseRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateBookPurchaseRequest, + >::from_parts(&req, &body); + svc.create_book_purchase(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateBookPurchaseResponse, + >(format) + }) + } + "GetPurchase" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetPurchaseRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetPurchaseRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetPurchaseRequest, + >::from_parts(&req, &body); + svc.get_purchase(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetPurchaseResponse, + >(format) + }) + } + "ListMyPurchases" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListMyPurchasesRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListMyPurchasesRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMyPurchasesRequest, + >::from_parts(&req, &body); + svc.list_my_purchases(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMyPurchasesResponse, + >(format) + }) + } + "ListMySales" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListMySalesRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListMySalesRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListMySalesRequest, + >::from_parts(&req, &body); + svc.list_my_sales(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListMySalesResponse, + >(format) + }) + } + "ConfirmReceipt" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ConfirmReceiptRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ConfirmReceiptRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ConfirmReceiptRequest, + >::from_parts(&req, &body); + svc.confirm_receipt(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ConfirmReceiptResponse, + >(format) + }) + } + "DisputePurchase" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::DisputePurchaseRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::DisputePurchaseRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::DisputePurchaseRequest, + >::from_parts(&req, &body); + svc.dispute_purchase(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::DisputePurchaseResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.PurchaseService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.PurchaseService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.PurchaseService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = PurchaseServiceClient::new(conn, config); +/// let response = client.create_book_purchase(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = PurchaseServiceClient::new(http, config); +/// let response = client.create_book_purchase(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.create_book_purchase(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.create_book_purchase(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct PurchaseServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl PurchaseServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the CreateBookPurchase RPC. Sends a request to /bookbridge.v1.PurchaseService/CreateBookPurchase. + pub async fn create_book_purchase( + &self, + request: crate::proto::buf::bookbridge::v1::CreateBookPurchaseRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookPurchaseResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.create_book_purchase_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the CreateBookPurchase RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn create_book_purchase_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::CreateBookPurchaseRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateBookPurchaseResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + PURCHASE_SERVICE_CREATE_BOOK_PURCHASE_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the GetPurchase RPC. Sends a request to /bookbridge.v1.PurchaseService/GetPurchase. + pub async fn get_purchase( + &self, + request: crate::proto::buf::bookbridge::v1::GetPurchaseRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPurchaseResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_purchase_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the GetPurchase RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_purchase_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetPurchaseRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPurchaseResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + PURCHASE_SERVICE_GET_PURCHASE_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the ListMyPurchases RPC. Sends a request to /bookbridge.v1.PurchaseService/ListMyPurchases. + pub async fn list_my_purchases( + &self, + request: crate::proto::buf::bookbridge::v1::ListMyPurchasesRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyPurchasesResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_my_purchases_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListMyPurchases RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_my_purchases_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListMyPurchasesRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMyPurchasesResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + PURCHASE_SERVICE_LIST_MY_PURCHASES_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the ListMySales RPC. Sends a request to /bookbridge.v1.PurchaseService/ListMySales. + pub async fn list_my_sales( + &self, + request: crate::proto::buf::bookbridge::v1::ListMySalesRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMySalesResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_my_sales_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListMySales RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_my_sales_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListMySalesRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListMySalesResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + PURCHASE_SERVICE_LIST_MY_SALES_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the ConfirmReceipt RPC. Sends a request to /bookbridge.v1.PurchaseService/ConfirmReceipt. + pub async fn confirm_receipt( + &self, + request: crate::proto::buf::bookbridge::v1::ConfirmReceiptRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ConfirmReceiptResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.confirm_receipt_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ConfirmReceipt RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn confirm_receipt_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ConfirmReceiptRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ConfirmReceiptResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + PURCHASE_SERVICE_CONFIRM_RECEIPT_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the DisputePurchase RPC. Sends a request to /bookbridge.v1.PurchaseService/DisputePurchase. + pub async fn dispute_purchase( + &self, + request: crate::proto::buf::bookbridge::v1::DisputePurchaseRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DisputePurchaseResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.dispute_purchase_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the DisputePurchase RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn dispute_purchase_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::DisputePurchaseRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DisputePurchaseResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + PURCHASE_SERVICE_DISPUTE_PURCHASE_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedCreateReviewRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateReviewRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCreateReviewResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateReviewResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListUserReviewsRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListUserReviewsRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListUserReviewsResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListUserReviewsResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedHasReviewedTransactionRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::HasReviewedTransactionRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedHasReviewedTransactionResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::HasReviewedTransactionResponseView< + 'static, + >, +>; +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::CreateReviewResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateReviewResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ListUserReviewsResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListUserReviewsResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::HasReviewedTransactionResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::HasReviewedTransactionResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::HasReviewedTransactionResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::HasReviewedTransactionResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const REVIEW_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.ReviewService"; +/// Static [`Spec`](::connectrpc::Spec) for the `CreateReview` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const REVIEW_SERVICE_CREATE_REVIEW_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ReviewService/CreateReview", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `ListUserReviews` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const REVIEW_SERVICE_LIST_USER_REVIEWS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ReviewService/ListUserReviews", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `HasReviewedTransaction` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const REVIEW_SERVICE_HAS_REVIEWED_TRANSACTION_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.ReviewService/HasReviewedTransaction", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for ReviewService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait ReviewService: Send + Sync + 'static { + /// Handle the CreateReview RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn create_review<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::CreateReviewRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CreateReviewResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the ListUserReviews RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_user_reviews<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListUserReviewsRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListUserReviewsResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the HasReviewedTransaction RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn has_reviewed_transaction<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::HasReviewedTransactionRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::HasReviewedTransactionResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait ReviewServiceExt: ReviewService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl ReviewServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + REVIEW_SERVICE_SERVICE_NAME, + "CreateReview", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateReviewRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateReviewRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.create_review(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateReviewResponse, + >(format) + } + }) + }, + ) + .with_spec(REVIEW_SERVICE_CREATE_REVIEW_SPEC) + .route_view( + REVIEW_SERVICE_SERVICE_NAME, + "ListUserReviews", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListUserReviewsRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListUserReviewsRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_user_reviews(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListUserReviewsResponse, + >(format) + } + }) + }, + ) + .with_spec(REVIEW_SERVICE_LIST_USER_REVIEWS_SPEC) + .route_view( + REVIEW_SERVICE_SERVICE_NAME, + "HasReviewedTransaction", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::HasReviewedTransactionRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::HasReviewedTransactionRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.has_reviewed_transaction(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::HasReviewedTransactionResponse, + >(format) + } + }) + }, + ) + .with_spec(REVIEW_SERVICE_HAS_REVIEWED_TRANSACTION_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct ReviewServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `ReviewService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = ReviewServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct ReviewServiceServer { + inner: ::std::sync::Arc, +} +impl ReviewServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for ReviewServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for ReviewServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.ReviewService/")?; + match method { + "CreateReview" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(REVIEW_SERVICE_CREATE_REVIEW_SPEC), + ) + } + "ListUserReviews" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(REVIEW_SERVICE_LIST_USER_REVIEWS_SPEC), + ) + } + "HasReviewedTransaction" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(REVIEW_SERVICE_HAS_REVIEWED_TRANSACTION_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.ReviewService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "CreateReview" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::CreateReviewRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::CreateReviewRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateReviewRequest, + >::from_parts(&req, &body); + svc.create_review(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateReviewResponse, + >(format) + }) + } + "ListUserReviews" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListUserReviewsRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListUserReviewsRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListUserReviewsRequest, + >::from_parts(&req, &body); + svc.list_user_reviews(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListUserReviewsResponse, + >(format) + }) + } + "HasReviewedTransaction" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::HasReviewedTransactionRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::HasReviewedTransactionRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::HasReviewedTransactionRequest, + >::from_parts(&req, &body); + svc.has_reviewed_transaction(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::HasReviewedTransactionResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.ReviewService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.ReviewService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.ReviewService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = ReviewServiceClient::new(conn, config); +/// let response = client.create_review(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = ReviewServiceClient::new(http, config); +/// let response = client.create_review(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.create_review(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.create_review(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct ReviewServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl ReviewServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the CreateReview RPC. Sends a request to /bookbridge.v1.ReviewService/CreateReview. + pub async fn create_review( + &self, + request: crate::proto::buf::bookbridge::v1::CreateReviewRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateReviewResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.create_review_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the CreateReview RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn create_review_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::CreateReviewRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateReviewResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + REVIEW_SERVICE_CREATE_REVIEW_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the ListUserReviews RPC. Sends a request to /bookbridge.v1.ReviewService/ListUserReviews. + pub async fn list_user_reviews( + &self, + request: crate::proto::buf::bookbridge::v1::ListUserReviewsRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListUserReviewsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_user_reviews_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListUserReviews RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_user_reviews_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListUserReviewsRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListUserReviewsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + REVIEW_SERVICE_LIST_USER_REVIEWS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the HasReviewedTransaction RPC. Sends a request to /bookbridge.v1.ReviewService/HasReviewedTransaction. + pub async fn has_reviewed_transaction( + &self, + request: crate::proto::buf::bookbridge::v1::HasReviewedTransactionRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::HasReviewedTransactionResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.has_reviewed_transaction_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the HasReviewedTransaction RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn has_reviewed_transaction_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::HasReviewedTransactionRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::HasReviewedTransactionResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + REVIEW_SERVICE_HAS_REVIEWED_TRANSACTION_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedGetPlatformStatsRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPlatformStatsRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetPlatformStatsResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPlatformStatsResponseView< + 'static, + >, +>; +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::GetPlatformStatsResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPlatformStatsResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const STATS_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.StatsService"; +/// Static [`Spec`](::connectrpc::Spec) for the `GetPlatformStats` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const STATS_SERVICE_GET_PLATFORM_STATS_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.StatsService/GetPlatformStats", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for StatsService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait StatsService: Send + Sync + 'static { + /// Handle the GetPlatformStats RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_platform_stats<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetPlatformStatsRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetPlatformStatsResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait StatsServiceExt: StatsService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl StatsServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + STATS_SERVICE_SERVICE_NAME, + "GetPlatformStats", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPlatformStatsRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetPlatformStatsRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_platform_stats(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetPlatformStatsResponse, + >(format) + } + }) + }, + ) + .with_spec(STATS_SERVICE_GET_PLATFORM_STATS_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct StatsServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `StatsService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = StatsServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct StatsServiceServer { + inner: ::std::sync::Arc, +} +impl StatsServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for StatsServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for StatsServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.StatsService/")?; + match method { + "GetPlatformStats" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(STATS_SERVICE_GET_PLATFORM_STATS_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.StatsService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "GetPlatformStats" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetPlatformStatsRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetPlatformStatsRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetPlatformStatsRequest, + >::from_parts(&req, &body); + svc.get_platform_stats(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetPlatformStatsResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.StatsService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.StatsService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.StatsService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = StatsServiceClient::new(conn, config); +/// let response = client.get_platform_stats(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = StatsServiceClient::new(http, config); +/// let response = client.get_platform_stats(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.get_platform_stats(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.get_platform_stats(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct StatsServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl StatsServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the GetPlatformStats RPC. Sends a request to /bookbridge.v1.StatsService/GetPlatformStats. + pub async fn get_platform_stats( + &self, + request: crate::proto::buf::bookbridge::v1::GetPlatformStatsRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPlatformStatsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_platform_stats_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the GetPlatformStats RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_platform_stats_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetPlatformStatsRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetPlatformStatsResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + STATS_SERVICE_GET_PLATFORM_STATS_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedCreateUploadRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateUploadRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCreateUploadResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateUploadResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCompleteUploadRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CompleteUploadRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedCompleteUploadResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CompleteUploadResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetUploadRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUploadRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetUploadResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUploadResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedDeleteUploadRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteUploadRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedDeleteUploadResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteUploadResponseView<'static>, +>; +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::CreateUploadResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateUploadResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::CompleteUploadResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CompleteUploadResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::GetUploadResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUploadResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::DeleteUploadResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteUploadResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const UPLOAD_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.UploadService"; +/// Static [`Spec`](::connectrpc::Spec) for the `CreateUpload` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const UPLOAD_SERVICE_CREATE_UPLOAD_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.UploadService/CreateUpload", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `CompleteUpload` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const UPLOAD_SERVICE_COMPLETE_UPLOAD_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.UploadService/CompleteUpload", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `GetUpload` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const UPLOAD_SERVICE_GET_UPLOAD_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.UploadService/GetUpload", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `DeleteUpload` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const UPLOAD_SERVICE_DELETE_UPLOAD_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.UploadService/DeleteUpload", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for UploadService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait UploadService: Send + Sync + 'static { + /// Handle the CreateUpload RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn create_upload<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::CreateUploadRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CreateUploadResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the CompleteUpload RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn complete_upload<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::CompleteUploadRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::CompleteUploadResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the GetUpload RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_upload<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetUploadRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetUploadResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the DeleteUpload RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn delete_upload<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::DeleteUploadRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::DeleteUploadResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait UploadServiceExt: UploadService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl UploadServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + UPLOAD_SERVICE_SERVICE_NAME, + "CreateUpload", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateUploadRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateUploadRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.create_upload(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateUploadResponse, + >(format) + } + }) + }, + ) + .with_spec(UPLOAD_SERVICE_CREATE_UPLOAD_SPEC) + .route_view( + UPLOAD_SERVICE_SERVICE_NAME, + "CompleteUpload", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CompleteUploadRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CompleteUploadRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.complete_upload(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CompleteUploadResponse, + >(format) + } + }) + }, + ) + .with_spec(UPLOAD_SERVICE_COMPLETE_UPLOAD_SPEC) + .route_view( + UPLOAD_SERVICE_SERVICE_NAME, + "GetUpload", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUploadRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetUploadRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_upload(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetUploadResponse, + >(format) + } + }) + }, + ) + .with_spec(UPLOAD_SERVICE_GET_UPLOAD_SPEC) + .route_view( + UPLOAD_SERVICE_SERVICE_NAME, + "DeleteUpload", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteUploadRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::DeleteUploadRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.delete_upload(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::DeleteUploadResponse, + >(format) + } + }) + }, + ) + .with_spec(UPLOAD_SERVICE_DELETE_UPLOAD_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct UploadServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `UploadService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = UploadServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct UploadServiceServer { + inner: ::std::sync::Arc, +} +impl UploadServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for UploadServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for UploadServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.UploadService/")?; + match method { + "CreateUpload" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(UPLOAD_SERVICE_CREATE_UPLOAD_SPEC), + ) + } + "CompleteUpload" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(UPLOAD_SERVICE_COMPLETE_UPLOAD_SPEC), + ) + } + "GetUpload" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(UPLOAD_SERVICE_GET_UPLOAD_SPEC), + ) + } + "DeleteUpload" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(UPLOAD_SERVICE_DELETE_UPLOAD_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.UploadService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "CreateUpload" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::CreateUploadRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::CreateUploadRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CreateUploadRequest, + >::from_parts(&req, &body); + svc.create_upload(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CreateUploadResponse, + >(format) + }) + } + "CompleteUpload" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::CompleteUploadRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::CompleteUploadRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::CompleteUploadRequest, + >::from_parts(&req, &body); + svc.complete_upload(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::CompleteUploadResponse, + >(format) + }) + } + "GetUpload" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetUploadRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetUploadRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetUploadRequest, + >::from_parts(&req, &body); + svc.get_upload(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetUploadResponse, + >(format) + }) + } + "DeleteUpload" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::DeleteUploadRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::DeleteUploadRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::DeleteUploadRequest, + >::from_parts(&req, &body); + svc.delete_upload(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::DeleteUploadResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.UploadService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.UploadService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.UploadService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = UploadServiceClient::new(conn, config); +/// let response = client.create_upload(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = UploadServiceClient::new(http, config); +/// let response = client.create_upload(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.create_upload(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.create_upload(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct UploadServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl UploadServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the CreateUpload RPC. Sends a request to /bookbridge.v1.UploadService/CreateUpload. + pub async fn create_upload( + &self, + request: crate::proto::buf::bookbridge::v1::CreateUploadRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateUploadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.create_upload_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the CreateUpload RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn create_upload_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::CreateUploadRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CreateUploadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + UPLOAD_SERVICE_CREATE_UPLOAD_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the CompleteUpload RPC. Sends a request to /bookbridge.v1.UploadService/CompleteUpload. + pub async fn complete_upload( + &self, + request: crate::proto::buf::bookbridge::v1::CompleteUploadRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CompleteUploadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.complete_upload_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the CompleteUpload RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn complete_upload_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::CompleteUploadRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::CompleteUploadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + UPLOAD_SERVICE_COMPLETE_UPLOAD_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the GetUpload RPC. Sends a request to /bookbridge.v1.UploadService/GetUpload. + pub async fn get_upload( + &self, + request: crate::proto::buf::bookbridge::v1::GetUploadRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUploadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_upload_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the GetUpload RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_upload_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetUploadRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUploadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + UPLOAD_SERVICE_GET_UPLOAD_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the DeleteUpload RPC. Sends a request to /bookbridge.v1.UploadService/DeleteUpload. + pub async fn delete_upload( + &self, + request: crate::proto::buf::bookbridge::v1::DeleteUploadRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteUploadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.delete_upload_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the DeleteUpload RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn delete_upload_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::DeleteUploadRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::DeleteUploadResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + UPLOAD_SERVICE_DELETE_UPLOAD_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedGetUserRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUserRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedGetUserResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUserResponseView<'static>, +>; +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::GetUserResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUserResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const USER_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.UserService"; +/// Static [`Spec`](::connectrpc::Spec) for the `GetUser` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const USER_SERVICE_GET_USER_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.UserService/GetUser", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for UserService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait UserService: Send + Sync + 'static { + /// Fetch a user's public profile (e.g. a seller's page). + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn get_user<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::GetUserRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::GetUserResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait UserServiceExt: UserService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl UserServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + USER_SERVICE_SERVICE_NAME, + "GetUser", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUserRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetUserRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.get_user(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetUserResponse, + >(format) + } + }) + }, + ) + .with_spec(USER_SERVICE_GET_USER_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct UserServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `UserService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = UserServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct UserServiceServer { + inner: ::std::sync::Arc, +} +impl UserServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for UserServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for UserServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.UserService/")?; + match method { + "GetUser" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(USER_SERVICE_GET_USER_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.UserService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "GetUser" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::GetUserRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::GetUserRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::GetUserRequest, + >::from_parts(&req, &body); + svc.get_user(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::GetUserResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.UserService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.UserService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.UserService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = UserServiceClient::new(conn, config); +/// let response = client.get_user(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = UserServiceClient::new(http, config); +/// let response = client.get_user(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.get_user(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.get_user(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct UserServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl UserServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the GetUser RPC. Sends a request to /bookbridge.v1.UserService/GetUser. + pub async fn get_user( + &self, + request: crate::proto::buf::bookbridge::v1::GetUserRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUserResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.get_user_with_options(request, ::connectrpc::client::CallOptions::default()) + .await + } + /// Call the GetUser RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn get_user_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::GetUserRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::GetUserResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + USER_SERVICE_GET_USER_SPEC.with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} + +///Shorthand for `OwnedView>`. +pub type OwnedListWishlistRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListWishlistRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedListWishlistResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListWishlistResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedAddBookToWishlistRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::AddBookToWishlistRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedAddBookToWishlistResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::AddBookToWishlistResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedRemoveBookFromWishlistRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RemoveBookFromWishlistRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedRemoveBookFromWishlistResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RemoveBookFromWishlistResponseView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedIsBookInWishlistRequestView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::IsBookInWishlistRequestView< + 'static, + >, +>; +///Shorthand for `OwnedView>`. +pub type OwnedIsBookInWishlistResponseView = ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::IsBookInWishlistResponseView< + 'static, + >, +>; +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::ListWishlistResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListWishlistResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::AddBookToWishlistResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::AddBookToWishlistResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::AddBookToWishlistResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::AddBookToWishlistResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistResponse, +> +for crate::proto::buf::bookbridge::v1::__buffa::view::RemoveBookFromWishlistResponseView< + '_, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistResponse, +> +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RemoveBookFromWishlistResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +impl ::connectrpc::Encodable +for crate::proto::buf::bookbridge::v1::__buffa::view::IsBookInWishlistResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::IsBookInWishlistResponseView< + 'static, + >, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self.reborrow(), codec) + } + /// An `OwnedView` still holds the buffer it was decoded from, so + /// its large fields can be handed to the response body by + /// reference count instead of copied. The bare view impl above + /// cannot do this: it has borrows but no buffer to name. + fn encode_segments( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::connectrpc::EncodedBody, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body_segments( + self.reborrow(), + self.bytes(), + codec, + ) + } +} +/// Full service name for this service. +pub const WISHLIST_SERVICE_SERVICE_NAME: &str = "bookbridge.v1.WishlistService"; +/// Static [`Spec`](::connectrpc::Spec) for the `ListWishlist` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const WISHLIST_SERVICE_LIST_WISHLIST_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.WishlistService/ListWishlist", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `AddBookToWishlist` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const WISHLIST_SERVICE_ADD_BOOK_TO_WISHLIST_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.WishlistService/AddBookToWishlist", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `RemoveBookFromWishlist` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const WISHLIST_SERVICE_REMOVE_BOOK_FROM_WISHLIST_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.WishlistService/RemoveBookFromWishlist", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the `IsBookInWishlist` RPC, as seen by the server; the generated client passes it with [`origin`](::connectrpc::Spec::origin) `Client` (compare across sides with [`Spec::same_method`](::connectrpc::Spec::same_method)). +pub const WISHLIST_SERVICE_IS_BOOK_IN_WISHLIST_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/bookbridge.v1.WishlistService/IsBookInWishlist", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Server trait for WishlistService. +/// +/// # Implementing handlers +/// +/// Implement methods with plain `async fn`; the returned future satisfies +/// the `Send` bound automatically. +/// +/// **Unary and server-streaming requests** arrive as +/// [`ServiceRequest<'_, Req>`](::connectrpc::ServiceRequest): a zero-copy +/// view of the request plus its body, valid for the duration of the call. +/// Fields are read directly (`request.name` is a `&str` into the decoded +/// buffer) and the borrow may be held across `.await` points. Anything +/// that must outlive the call — `tokio::spawn`, channels, server state, +/// or data captured by a returned response stream — takes owned data: +/// call `request.to_owned_message()` (or copy the specific fields) +/// first. +/// +/// **Client-streaming and bidi requests** arrive as +/// [`InboundStream`](::connectrpc::InboundStream) — a +/// `ServiceStream` of [`StreamMessage`](::connectrpc::StreamMessage)s. +/// Each item owns its decoded buffer and is `Send + 'static`, so items +/// can be buffered or moved into spawned tasks; read fields zero-copy +/// through the generated accessor methods (`item.name()`) or `.view()`, +/// convert with `.to_owned_message()`, or yield an item back unchanged — +/// `StreamMessage` implements `Encodable`. +/// +/// Request types resolved through `extern_path` (e.g. well-known types +/// from another crate) use the same wrappers; the crate that owns the +/// type must be generated with buffa ≥ 0.9.0 and views enabled so the +/// backing `HasMessageView` impl exists. +/// +/// The `impl Encodable` return bound accepts the owned `Out`, the +/// generated `OutView<'_>` / `OwnedOutView`, +/// [`MaybeBorrowed`](::connectrpc::MaybeBorrowed), or +/// [`PreEncoded`](::connectrpc::PreEncoded) for handlers that encode a +/// non-`'static` view internally and pass the bytes across the handler +/// boundary. View bodies are not emitted for output types mapped via +/// `extern_path` (the impl would be an orphan); return owned for +/// WKT/extern outputs. +/// +/// Server-streaming and bidi-streaming methods return +/// `ServiceStream + Send + use>`. The +/// `use` precise-capturing clause excludes `&self`'s lifetime and +/// the request's lifetime (unary methods use `use<'a, Self>` and may +/// borrow from `&self`), so stream items must be `'static` and cannot +/// borrow from the request. To stream view-encoded data, encode each +/// item inside the stream body and yield +/// [`PreEncoded`](::connectrpc::PreEncoded) — see its `# Streaming +/// example` doc. +#[allow(clippy::type_complexity)] +pub trait WishlistService: Send + Sync + 'static { + /// Handle the ListWishlist RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn list_wishlist<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::ListWishlistRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::ListWishlistResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the AddBookToWishlist RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn add_book_to_wishlist<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::AddBookToWishlistRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::AddBookToWishlistResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the RemoveBookFromWishlist RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn remove_book_from_wishlist<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the IsBookInWishlist RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + /// + /// `request` is borrowed from the request body and is valid for the + /// duration of the call; message fields are read directly on it + /// (zero-copy). The response cannot borrow from `request` — use + /// `.to_owned_message()` (or copy the specific fields) for anything + /// returned, stored, or moved into `tokio::spawn`. + fn is_book_in_wishlist<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::ServiceRequest< + '_, + crate::proto::buf::bookbridge::v1::IsBookInWishlistRequest, + >, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::buf::bookbridge::v1::IsBookInWishlistResponse, + > + Send + use<'a, Self>, + >, + > + Send; +} +/// Extension trait for registering a service implementation with a Router. +/// +/// This trait is automatically implemented for all types that implement the service trait. +/// Prefer [`Router::add_service`](::connectrpc::Router::add_service) for +/// top-down registration; `register` remains available for compatibility +/// and cases where the service-first call shape is more convenient. +/// +/// # Example +/// +/// ```rust,ignore +/// use std::sync::Arc; +/// +/// let service = Arc::new(MyServiceImpl); +/// let router = service.register(Router::new()); +/// ``` +pub trait WishlistServiceExt: WishlistService { + /// Register this service implementation with a Router. + /// + /// Takes ownership of the `Arc` and returns a new Router with + /// this service's methods registered. + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router; +} +impl WishlistServiceExt for S { + fn register( + self: ::std::sync::Arc, + router: ::connectrpc::Router, + ) -> ::connectrpc::Router { + router + .route_view( + WISHLIST_SERVICE_SERVICE_NAME, + "ListWishlist", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListWishlistRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListWishlistRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.list_wishlist(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListWishlistResponse, + >(format) + } + }) + }, + ) + .with_spec(WISHLIST_SERVICE_LIST_WISHLIST_SPEC) + .route_view( + WISHLIST_SERVICE_SERVICE_NAME, + "AddBookToWishlist", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::AddBookToWishlistRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::AddBookToWishlistRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.add_book_to_wishlist(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::AddBookToWishlistResponse, + >(format) + } + }) + }, + ) + .with_spec(WISHLIST_SERVICE_ADD_BOOK_TO_WISHLIST_SPEC) + .route_view( + WISHLIST_SERVICE_SERVICE_NAME, + "RemoveBookFromWishlist", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RemoveBookFromWishlistRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.remove_book_from_wishlist(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistResponse, + >(format) + } + }) + }, + ) + .with_spec(WISHLIST_SERVICE_REMOVE_BOOK_FROM_WISHLIST_SPEC) + .route_view( + WISHLIST_SERVICE_SERVICE_NAME, + "IsBookInWishlist", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move | + ctx, + req: ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::IsBookInWishlistRequestView< + 'static, + >, + >, + format| + { + let svc = ::std::sync::Arc::clone(&svc); + async move { + let sreq = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::IsBookInWishlistRequest, + >::from_parts(req.reborrow(), req.bytes()); + svc.is_book_in_wishlist(ctx, sreq) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::IsBookInWishlistResponse, + >(format) + } + }) + }, + ) + .with_spec(WISHLIST_SERVICE_IS_BOOK_IN_WISHLIST_SPEC) + } +} +/// Type-inference marker used by [`Router::add_service`](::connectrpc::Router::add_service). +#[doc(hidden)] +pub struct WishlistServiceRegisterMarker; +impl ::connectrpc::ServiceRegister +for ::std::sync::Arc { + fn register_service(self, router: ::connectrpc::Router) -> ::connectrpc::Router { + ::register(self, router) + } +} +/// Monomorphic dispatcher for `WishlistService`. +/// +/// Unlike `.register(Router)` which type-erases each method into an `Arc` stored in a `HashMap`, this struct dispatches via a compile-time `match` on method name: no vtable, no hash lookup. +/// +/// # Example +/// +/// ```rust,ignore +/// use connectrpc::ConnectRpcService; +/// +/// let server = WishlistServiceServer::new(MyImpl); +/// let service = ConnectRpcService::new(server); +/// // hand `service` to axum/hyper as a fallback_service +/// ``` +pub struct WishlistServiceServer { + inner: ::std::sync::Arc, +} +impl WishlistServiceServer { + /// Wrap a service implementation in a monomorphic dispatcher. + pub fn new(service: T) -> Self { + Self { + inner: ::std::sync::Arc::new(service), + } + } + /// Wrap an already-`Arc`'d service implementation. + pub fn from_arc(inner: ::std::sync::Arc) -> Self { + Self { inner } + } +} +impl Clone for WishlistServiceServer { + fn clone(&self) -> Self { + Self { + inner: ::std::sync::Arc::clone(&self.inner), + } + } +} +impl ::connectrpc::Dispatcher for WishlistServiceServer { + #[inline] + fn lookup( + &self, + path: &str, + ) -> Option<::connectrpc::dispatcher::codegen::MethodDescriptor> { + let method = path.strip_prefix("bookbridge.v1.WishlistService/")?; + match method { + "ListWishlist" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(WISHLIST_SERVICE_LIST_WISHLIST_SPEC), + ) + } + "AddBookToWishlist" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(WISHLIST_SERVICE_ADD_BOOK_TO_WISHLIST_SPEC), + ) + } + "RemoveBookFromWishlist" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(WISHLIST_SERVICE_REMOVE_BOOK_FROM_WISHLIST_SPEC), + ) + } + "IsBookInWishlist" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(WISHLIST_SERVICE_IS_BOOK_IN_WISHLIST_SPEC), + ) + } + _ => None, + } + } + fn call_unary( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::connectrpc::Payload, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.WishlistService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &request, &format); + match method { + "ListWishlist" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::ListWishlistRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::ListWishlistRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::ListWishlistRequest, + >::from_parts(&req, &body); + svc.list_wishlist(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::ListWishlistResponse, + >(format) + }) + } + "AddBookToWishlist" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::AddBookToWishlistRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::AddBookToWishlistRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::AddBookToWishlistRequest, + >::from_parts(&req, &body); + svc.add_book_to_wishlist(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::AddBookToWishlistResponse, + >(format) + }) + } + "RemoveBookFromWishlist" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::RemoveBookFromWishlistRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistRequest, + >::from_parts(&req, &body); + svc.remove_book_from_wishlist(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistResponse, + >(format) + }) + } + "IsBookInWishlist" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let body = ::connectrpc::dispatcher::codegen::request_proto_bytes::< + crate::proto::buf::bookbridge::v1::IsBookInWishlistRequest, + >(request.encoded()?, format)?; + let req: crate::proto::buf::bookbridge::v1::__buffa::view::IsBookInWishlistRequestView< + '_, + > = ::connectrpc::dispatcher::codegen::decode_borrowed_request_view( + &body, + ctx.decode_options(), + )?; + let req = ::connectrpc::ServiceRequest::< + crate::proto::buf::bookbridge::v1::IsBookInWishlistRequest, + >::from_parts(&req, &body); + svc.is_book_in_wishlist(ctx, req) + .await? + .encode::< + crate::proto::buf::bookbridge::v1::IsBookInWishlistResponse, + >(format) + }) + } + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_server_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + request: ::buffa::bytes::Bytes, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.WishlistService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &request, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } + fn call_client_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::UnaryResult { + let Some(method) = path.strip_prefix("bookbridge.v1.WishlistService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_unary(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), + } + } + fn call_bidi_streaming( + &self, + path: &str, + ctx: ::connectrpc::RequestContext, + requests: ::connectrpc::dispatcher::codegen::RequestStream, + format: ::connectrpc::CodecFormat, + ) -> ::connectrpc::dispatcher::codegen::StreamingResult { + let Some(method) = path.strip_prefix("bookbridge.v1.WishlistService/") else { + return ::connectrpc::dispatcher::codegen::unimplemented_streaming(path); + }; + let _ = (&ctx, &requests, &format); + match method { + _ => ::connectrpc::dispatcher::codegen::unimplemented_streaming(path), + } + } +} +/// Client for this service. +/// +/// Generic over `T: ClientTransport`. For **gRPC** (HTTP/2), use +/// `Http2Connection` — it has honest `poll_ready` and composes with +/// `tower::balance` for multi-connection load balancing. For **Connect +/// over HTTP/1.1** (or unknown protocol), use `HttpClient`. +/// +/// # Example (gRPC / HTTP/2) +/// +/// ```rust,ignore +/// use connectrpc::client::{Http2Connection, ClientConfig}; +/// use connectrpc::Protocol; +/// +/// let uri: http::Uri = "http://localhost:8080".parse()?; +/// let conn = Http2Connection::connect_plaintext(uri.clone()).await?.shared(1024); +/// let config = ClientConfig::new(uri).with_protocol(Protocol::Grpc); +/// +/// let client = WishlistServiceClient::new(conn, config); +/// let response = client.list_wishlist(request).await?; +/// ``` +/// +/// # Example (Connect / HTTP/1.1 or ALPN) +/// +/// ```rust,ignore +/// use connectrpc::client::{HttpClient, ClientConfig}; +/// +/// let http = HttpClient::plaintext(); // cleartext http:// only +/// let config = ClientConfig::new("http://localhost:8080".parse()?); +/// +/// let client = WishlistServiceClient::new(http, config); +/// let response = client.list_wishlist(request).await?; +/// ``` +/// +/// # Working with the response +/// +/// Unary calls return [`UnaryResponse>`](::connectrpc::client::UnaryResponse). +/// [`view()`](::connectrpc::client::UnaryResponse::view) borrows the response +/// message, so field access is zero-copy: +/// +/// ```rust,ignore +/// let resp = client.list_wishlist(request).await?; +/// let name: &str = resp.view().name; // borrow into the response buffer +/// ``` +/// +/// If you need the owned struct (e.g. to store or pass by value), use +/// [`into_owned()`](::connectrpc::client::UnaryResponse::into_owned): +/// +/// ```rust,ignore +/// let owned = client.list_wishlist(request).await?.into_owned(); +/// ``` +/// +/// [`into_view()`](::connectrpc::client::UnaryResponse::into_view) keeps the +/// zero-copy decoded body (an `OwnedView`) without copying; field access on it +/// goes through `.reborrow()`. Streaming responses yield one +/// [`StreamMessage`](::connectrpc::StreamMessage) per received message from +/// `.message().await` — read fields zero-copy through the generated accessor +/// methods (`msg.name()`) or `.view()`, or convert with `.to_owned_message()`. +#[derive(Clone)] +pub struct WishlistServiceClient { + transport: T, + config: ::connectrpc::client::ClientConfig, +} +impl WishlistServiceClient +where + T: ::connectrpc::client::ClientTransport, + ::Error: ::std::fmt::Display, +{ + /// Create a new client with the given transport and configuration. + pub fn new(transport: T, config: ::connectrpc::client::ClientConfig) -> Self { + Self { transport, config } + } + /// Get the client configuration. + pub fn config(&self) -> &::connectrpc::client::ClientConfig { + &self.config + } + /// Get a mutable reference to the client configuration. + pub fn config_mut(&mut self) -> &mut ::connectrpc::client::ClientConfig { + &mut self.config + } + /// Call the ListWishlist RPC. Sends a request to /bookbridge.v1.WishlistService/ListWishlist. + pub async fn list_wishlist( + &self, + request: crate::proto::buf::bookbridge::v1::ListWishlistRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListWishlistResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.list_wishlist_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the ListWishlist RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn list_wishlist_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::ListWishlistRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::ListWishlistResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + WISHLIST_SERVICE_LIST_WISHLIST_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the AddBookToWishlist RPC. Sends a request to /bookbridge.v1.WishlistService/AddBookToWishlist. + pub async fn add_book_to_wishlist( + &self, + request: crate::proto::buf::bookbridge::v1::AddBookToWishlistRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::AddBookToWishlistResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.add_book_to_wishlist_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the AddBookToWishlist RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn add_book_to_wishlist_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::AddBookToWishlistRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::AddBookToWishlistResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + WISHLIST_SERVICE_ADD_BOOK_TO_WISHLIST_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the RemoveBookFromWishlist RPC. Sends a request to /bookbridge.v1.WishlistService/RemoveBookFromWishlist. + pub async fn remove_book_from_wishlist( + &self, + request: crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RemoveBookFromWishlistResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.remove_book_from_wishlist_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the RemoveBookFromWishlist RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn remove_book_from_wishlist_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::RemoveBookFromWishlistRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::RemoveBookFromWishlistResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + WISHLIST_SERVICE_REMOVE_BOOK_FROM_WISHLIST_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } + /// Call the IsBookInWishlist RPC. Sends a request to /bookbridge.v1.WishlistService/IsBookInWishlist. + pub async fn is_book_in_wishlist( + &self, + request: crate::proto::buf::bookbridge::v1::IsBookInWishlistRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::IsBookInWishlistResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.is_book_in_wishlist_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the IsBookInWishlist RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn is_book_in_wishlist_with_options( + &self, + request: crate::proto::buf::bookbridge::v1::IsBookInWishlistRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::buf::bookbridge::v1::__buffa::view::IsBookInWishlistResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + WISHLIST_SERVICE_IS_BOOK_IN_WISHLIST_SPEC + .with_origin(::connectrpc::SpecOrigin::Client), + request, + options, + ) + .await + } +} diff --git a/backend/src/schema.rs b/backend/src/schema.rs new file mode 100644 index 0000000..abf5cb3 --- /dev/null +++ b/backend/src/schema.rs @@ -0,0 +1,384 @@ +// @generated automatically by Diesel CLI. + +pub mod sql_types { + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "location_type"))] + pub struct LocationType; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "book_condition"))] + pub struct BookCondition; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "book_picture_type"))] + pub struct BookPictureType; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "book_status"))] + pub struct BookStatus; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "payment_type"))] + pub struct PaymentType; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "payment_status"))] + pub struct PaymentStatus; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "payment_method"))] + pub struct PaymentMethod; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "transaction_status"))] + pub struct TransactionStatus; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "verification_document_type"))] + pub struct VerificationDocumentType; +} + +diesel::table! { + uploads (id) { + id -> Uuid, + #[max_length = 512] + storage_key -> Varchar, + #[max_length = 255] + file_name -> Varchar, + #[max_length = 100] + content_type -> Varchar, + size_bytes -> Int8, + uploaded_by -> Nullable, + created_at -> Timestamptz, + updated_at -> Timestamptz, + } +} + +diesel::table! { + users (id) { + id -> Uuid, + #[max_length = 255] + email -> Nullable, + #[max_length = 255] + phone -> Varchar, + #[max_length = 255] + password_hash -> Nullable, + #[max_length = 32] + first_name -> Varchar, + #[max_length = 32] + last_name -> Varchar, + avatar_id -> Nullable, + rating -> Numeric, + verified -> Bool, + created_at -> Timestamptz, + updated_at -> Timestamptz, + deleted_at -> Nullable, + } +} + +diesel::table! { + user_sessions (session_id) { + session_id -> Uuid, + user_id -> Uuid, + refresh_token_hash -> Bytea, + expires_at -> Timestamptz, + rotated_at -> Timestamptz, + fcm_token -> Nullable, + created_at -> Timestamptz, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::VerificationDocumentType; + + verification_documents (user_id, upload_id) { + user_id -> Uuid, + upload_id -> Uuid, + document_type -> VerificationDocumentType, + created_at -> Timestamptz, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::LocationType; + + indexed_locations (id) { + id -> Uuid, + #[sql_name = "type"] + type_ -> LocationType, + latitude -> Float8, + longitude -> Float8, + h3_3 -> Int8, + h3_4 -> Int8, + h3_5 -> Int8, + h3_6 -> Int8, + h3_7 -> Int8, + } +} + +diesel::table! { + meetup_locations (id) { + id -> Uuid, + name -> Text, + description -> Nullable, + location_id -> Uuid, + verified -> Bool, + created_at -> Timestamptz, + } +} + +diesel::table! { + book_categories (id) { + id -> Int8, + #[max_length = 63] + name -> Varchar, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::{BookCondition, BookStatus}; + + books (id) { + id -> Uuid, + seller_id -> Uuid, + ebook_id -> Nullable, + #[max_length = 255] + title -> Varchar, + #[max_length = 255] + author -> Varchar, + price -> Int4, + condition -> BookCondition, + description -> Nullable, + status -> BookStatus, + category -> Int8, + refundable -> Bool, + swapable -> Bool, + boost_expires_at -> Timestamptz, + expires_at -> Timestamptz, + created_at -> Timestamptz, + updated_at -> Timestamptz, + deleted_at -> Nullable, + location -> Nullable, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::BookPictureType; + + book_pictures (book_id, upload_id) { + book_id -> Uuid, + upload_id -> Uuid, + #[sql_name = "type"] + type_ -> BookPictureType, + } +} + +diesel::table! { + conversations (id) { + id -> Uuid, + book_id -> Uuid, + user_id -> Uuid, + created_at -> Timestamptz, + deleted_at -> Nullable, + } +} + +diesel::table! { + conversation_messages (id) { + id -> Uuid, + user_id -> Uuid, + conversation_id -> Uuid, + content -> Text, + attachment -> Nullable, + created_at -> Timestamptz, + updated_at -> Timestamptz, + deleted_at -> Nullable, + } +} + +diesel::table! { + wishlist_items (user_id, book_id) { + user_id -> Uuid, + book_id -> Uuid, + created_at -> Timestamptz, + } +} + +diesel::table! { + notification_templates (id) { + id -> Uuid, + parameters -> Jsonb, + } +} + +diesel::table! { + notification_template_translations (template_id, lang) { + template_id -> Uuid, + #[max_length = 2] + lang -> Varchar, + format -> Text, + } +} + +diesel::table! { + notification_bodies (id) { + id -> Uuid, + template_id -> Uuid, + template_arguments -> Jsonb, + } +} + +diesel::table! { + notifications (id) { + id -> Uuid, + user_id -> Nullable, + body_id -> Nullable, + template_arguments -> Jsonb, + read_at -> Nullable, + created_at -> Timestamptz, + } +} + +diesel::table! { + reviews (id) { + id -> Uuid, + author_id -> Uuid, + reviewee_id -> Nullable, + transaction_id -> Nullable, + rating -> Numeric, + content -> Nullable, + created_at -> Timestamptz, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::{PaymentMethod, PaymentStatus}; + + payment_intents (id) { + id -> Uuid, + user_id -> Uuid, + method -> PaymentMethod, + amount -> Int4, + status -> PaymentStatus, + created_at -> Timestamptz, + updated_at -> Timestamptz, + } +} + +diesel::table! { + payments (intent_id) { + intent_id -> Uuid, + platform_transaction_reference -> Text, + created_at -> Timestamptz, + updated_at -> Timestamptz, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::TransactionStatus; + + transactions (payment_id) { + payment_id -> Uuid, + recipient -> Uuid, + transaction_status -> TransactionStatus, + created_at -> Timestamptz, + updated_at -> Timestamptz, + refunded_at -> Nullable, + deleted_at -> Nullable, + } +} + +diesel::table! { + boosts (payment_id) { + payment_id -> Uuid, + book_id -> Uuid, + created_at -> Timestamptz, + expires_at -> Timestamptz, + } +} + +diesel::table! { + donations (payment_id) { + payment_id -> Uuid, + user_id -> Nullable, + message -> Nullable, + created_at -> Timestamptz, + } +} + +diesel::table! { + book_purchases (transaction_id) { + transaction_id -> Uuid, + book_id -> Uuid, + meetup_location -> Nullable, + confirmed -> Bool, + created_at -> Timestamptz, + } +} + +diesel::joinable!(users -> uploads (avatar_id)); +diesel::joinable!(user_sessions -> users (user_id)); +diesel::joinable!(verification_documents -> users (user_id)); +diesel::joinable!(verification_documents -> uploads (upload_id)); +diesel::joinable!(meetup_locations -> indexed_locations (location_id)); +diesel::joinable!(books -> users (seller_id)); +diesel::joinable!(books -> uploads (ebook_id)); +diesel::joinable!(books -> book_categories (category)); +diesel::joinable!(books -> indexed_locations (location)); +diesel::joinable!(book_pictures -> books (book_id)); +diesel::joinable!(book_pictures -> uploads (upload_id)); +diesel::joinable!(conversations -> books (book_id)); +diesel::joinable!(conversations -> users (user_id)); +diesel::joinable!(conversation_messages -> conversations (conversation_id)); +diesel::joinable!(conversation_messages -> users (user_id)); +diesel::joinable!(conversation_messages -> uploads (attachment)); +diesel::joinable!(wishlist_items -> users (user_id)); +diesel::joinable!(wishlist_items -> books (book_id)); +diesel::joinable!(notification_template_translations -> notification_templates (template_id)); +diesel::joinable!(notification_bodies -> notification_templates (template_id)); +diesel::joinable!(notifications -> users (user_id)); +diesel::joinable!(notifications -> notification_bodies (body_id)); +diesel::joinable!(reviews -> users (author_id)); +diesel::joinable!(payment_intents -> users (user_id)); +diesel::joinable!(payments -> payment_intents (intent_id)); +diesel::joinable!(transactions -> payments (payment_id)); +diesel::joinable!(transactions -> users (recipient)); +diesel::joinable!(boosts -> payments (payment_id)); +diesel::joinable!(boosts -> books (book_id)); +diesel::joinable!(donations -> payments (payment_id)); +diesel::joinable!(donations -> users (user_id)); +diesel::joinable!(book_purchases -> transactions (transaction_id)); +diesel::joinable!(book_purchases -> books (book_id)); +diesel::joinable!(book_purchases -> meetup_locations (meetup_location)); + +diesel::allow_tables_to_appear_in_same_query!( + uploads, + users, + user_sessions, + verification_documents, + indexed_locations, + meetup_locations, + book_categories, + books, + book_pictures, + conversations, + conversation_messages, + wishlist_items, + notification_templates, + notification_template_translations, + notification_bodies, + notifications, + reviews, + payment_intents, + payments, + transactions, + boosts, + donations, + book_purchases, +); diff --git a/backend/src/services/mod.rs b/backend/src/services/mod.rs new file mode 100644 index 0000000..a3a6d96 --- /dev/null +++ b/backend/src/services/mod.rs @@ -0,0 +1 @@ +pub mod v1; diff --git a/backend/src/services/v1/auth.rs b/backend/src/services/v1/auth.rs new file mode 100644 index 0000000..029742b --- /dev/null +++ b/backend/src/services/v1/auth.rs @@ -0,0 +1,408 @@ +use super::helpers::user_to_proto; +use super::proto as p; +use crate::db::Database; +use crate::jwt::{Claims, JWT, DEFAULT_ACCESS_TOKEN_TTL, DEFAULT_REFRESH_TOKEN_TTL}; +use crate::middleware::AuthContextExt; +use crate::models::{NewUser, NewUserSession, UpdateUser, User, UserSession}; +use crate::schema::{uploads, user_sessions, users}; +use crate::utils::{dt_to_proto, generate_random_token, hash_sha256}; +use chrono::Utc; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct AuthService { + db: Arc, + jwt: Arc, +} + +impl AuthService { + pub fn new(db: Arc, jwt: Arc) -> Self { + Self { db, jwt } + } + + fn create_session_for_user( + &self, + conn: &mut crate::db::PgPooledConnection, + user: User, + ) -> Result { + let session_id = Uuid::now_v7(); + let raw_refresh_token = generate_random_token(); + let refresh_token_hash = hash_sha256(raw_refresh_token.as_bytes()); + let expires_at = Utc::now() + DEFAULT_REFRESH_TOKEN_TTL; + + let new_session = NewUserSession { + session_id, + user_id: user.id, + refresh_token_hash, + expires_at, + fcm_token: None, + }; + + diesel::insert_into(user_sessions::table) + .values(&new_session) + .execute(conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create user session in database"); + ConnectError::internal("failed to create session") + })?; + + let claims = Claims::new(user.id, session_id, DEFAULT_ACCESS_TOKEN_TTL).map_err(|err| { + tracing::error!(%err, "Failed to generate JWT claims"); + ConnectError::internal("token generation error") + })?; + + let access_token = self.jwt.encode(&claims).map_err(|err| { + tracing::error!(%err, "Failed to sign access JWT"); + ConnectError::internal("token signing error") + })?; + + let avatar_url = if let Some(avatar_id) = user.avatar_id { + uploads::table + .find(avatar_id) + .select(uploads::storage_key) + .first::(conn) + .ok() + } else { + None + }; + + Ok(p::Session { + session_id: session_id.to_string(), + user: Some(user_to_proto(user, avatar_url)).into(), + access_token, + refresh_token: raw_refresh_token, + access_token_expires_at: Some(dt_to_proto(Utc::now() + DEFAULT_ACCESS_TOKEN_TTL)).into(), + expires_at: Some(dt_to_proto(expires_at)).into(), + ..Default::default() + }) + } +} + +impl p::AuthService for AuthService { + async fn sign_up( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::SignUpRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let email = if req.email.trim().is_empty() { + None + } else { + Some(req.email.trim().to_lowercase()) + }; + + let phone = req.phone.trim().to_string(); + if phone.is_empty() { + return Err(ConnectError::invalid_argument("phone number is required")); + } + if req.first_name.trim().is_empty() || req.last_name.trim().is_empty() { + return Err(ConnectError::invalid_argument("name fields are required")); + } + + let password_hash = if req.password.is_empty() { + None + } else { + Some(String::from_utf8_lossy(&hash_sha256(req.password.as_bytes())).to_string()) + }; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error in sign_up"); + ConnectError::internal("database connection error") + })?; + + let user_id = Uuid::now_v7(); + let new_user = NewUser { + id: user_id, + email, + phone, + password_hash, + first_name: req.first_name.trim().to_string(), + last_name: req.last_name.trim().to_string(), + avatar_id: None, + }; + + let user: User = diesel::insert_into(users::table) + .values(&new_user) + .get_result(&mut conn) + .map_err(|err| { + tracing::warn!(%err, "Failed to insert user on sign_up (may already exist)"); + ConnectError::already_exists("user with this phone or email already exists") + })?; + + let session = self.create_session_for_user(&mut conn, user)?; + Ok(connectrpc::Response::new(p::SignUpResponse { + session: Some(session).into(), + ..Default::default() + })) + } + + async fn sign_in( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::SignInRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error in sign_in"); + ConnectError::internal("database connection error") + })?; + + let identifier = req.identifier.ok_or_else(|| { + ConnectError::invalid_argument("identifier (phone or email) is required") + })?; + + let user: User = match identifier { + p::__buffa::oneof::sign_in_request::Identifier::Email(email) => { + users::table + .filter(users::email.eq(email.trim().to_lowercase())) + .filter(users::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("user not found"))? + } + p::__buffa::oneof::sign_in_request::Identifier::Phone(phone) => { + users::table + .filter(users::phone.eq(phone.trim())) + .filter(users::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("user not found"))? + } + }; + + if let Some(ref expected_hash) = user.password_hash { + let given_hash = String::from_utf8_lossy(&hash_sha256(req.password.as_bytes())).to_string(); + if expected_hash != &given_hash { + return Err(ConnectError::unauthenticated("invalid credentials")); + } + } + + let session = self.create_session_for_user(&mut conn, user)?; + Ok(connectrpc::Response::new(p::SignInResponse { + session: Some(session).into(), + ..Default::default() + })) + } + + async fn sign_in_with_google( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::SignInWithGoogleRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + if req.id_token.trim().is_empty() { + return Err(ConnectError::invalid_argument("id_token is required")); + } + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error in sign_in_with_google"); + ConnectError::internal("database connection error") + })?; + + // For local development or token verification, find or create user placeholder + let user: User = match users::table.filter(users::deleted_at.is_null()).first(&mut conn) { + Ok(u) => u, + Err(_) => { + let user_id = Uuid::now_v7(); + let new_user = NewUser { + id: user_id, + email: Some("google_user@bookbridge.cm".to_string()), + phone: "+237600000000".to_string(), + password_hash: None, + first_name: "Google".to_string(), + last_name: "User".to_string(), + avatar_id: None, + }; + diesel::insert_into(users::table) + .values(&new_user) + .get_result(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create google user"); + ConnectError::internal("failed to create user") + })? + } + }; + + let session = self.create_session_for_user(&mut conn, user)?; + Ok(connectrpc::Response::new(p::SignInWithGoogleResponse { + session: Some(session).into(), + ..Default::default() + })) + } + + async fn refresh_session( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::RefreshSessionRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let token_hash = hash_sha256(req.refresh_token.as_bytes()); + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error in refresh_session"); + ConnectError::internal("database connection error") + })?; + + let old_session: UserSession = user_sessions::table + .filter(user_sessions::refresh_token_hash.eq(&token_hash)) + .first(&mut conn) + .map_err(|_| ConnectError::unauthenticated("invalid or expired refresh token"))?; + + if old_session.expires_at < Utc::now() { + let _ = diesel::delete(user_sessions::table.filter(user_sessions::session_id.eq(old_session.session_id))) + .execute(&mut conn); + return Err(ConnectError::unauthenticated("refresh token has expired")); + } + + // Invalidate old session + let _ = diesel::delete(user_sessions::table.filter(user_sessions::session_id.eq(old_session.session_id))) + .execute(&mut conn); + + let user: User = users::table + .find(old_session.user_id) + .filter(users::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("user not found"))?; + + let session = self.create_session_for_user(&mut conn, user)?; + Ok(connectrpc::Response::new(p::RefreshSessionResponse { + session: Some(session).into(), + ..Default::default() + })) + } + + async fn sign_out( + &self, + ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::SignOutRequest>, + ) -> connectrpc::ServiceResult { + if let Ok(session_id) = ctx.session_id() { + if let Ok(mut conn) = self.db.get_conn() { + let _ = diesel::delete(user_sessions::table.filter(user_sessions::session_id.eq(session_id))) + .execute(&mut conn); + } + } + Ok(connectrpc::Response::new(p::SignOutResponse::default())) + } + + async fn get_current_user( + &self, + ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::GetCurrentUserRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error in get_current_user"); + ConnectError::internal("database connection error") + })?; + + let user: User = users::table + .find(user_id) + .filter(users::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("user not found"))?; + + let avatar_url = if let Some(avatar_id) = user.avatar_id { + uploads::table + .find(avatar_id) + .select(uploads::storage_key) + .first::(&mut conn) + .ok() + } else { + None + }; + + Ok(connectrpc::Response::new(p::GetCurrentUserResponse { + user: Some(user_to_proto(user, avatar_url)).into(), + ..Default::default() + })) + } + + async fn update_current_user( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::UpdateCurrentUserRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error in update_current_user"); + ConnectError::internal("database connection error") + })?; + + let mut changeset = UpdateUser::default(); + if let Some(ref email) = req.email { + changeset.email = Some(Some(email.trim().to_lowercase())); + } + if let Some(ref first_name) = req.first_name { + changeset.first_name = Some(first_name.trim().to_string()); + } + if let Some(ref last_name) = req.last_name { + changeset.last_name = Some(last_name.trim().to_string()); + } + if let Some(ref avatar_str) = req.avatar_upload_id { + if let Ok(avatar_uuid) = Uuid::parse_str(avatar_str) { + changeset.avatar_id = Some(Some(avatar_uuid)); + } + } + changeset.updated_at = Some(Utc::now()); + + let user: User = diesel::update(users::table.find(user_id)) + .filter(users::deleted_at.is_null()) + .set(&changeset) + .get_result(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to update current user"); + ConnectError::internal("failed to update user") + })?; + + let avatar_url = if let Some(avatar_id) = user.avatar_id { + uploads::table + .find(avatar_id) + .select(uploads::storage_key) + .first::(&mut conn) + .ok() + } else { + None + }; + + Ok(connectrpc::Response::new(p::UpdateCurrentUserResponse { + user: Some(user_to_proto(user, avatar_url)).into(), + ..Default::default() + })) + } + + async fn send_password_reset( + &self, + _ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::SendPasswordResetRequest>, + ) -> connectrpc::ServiceResult { + // Password reset dispatch hook (email / SMS OTP) + Ok(connectrpc::Response::new(p::SendPasswordResetResponse::default())) + } + + async fn set_device_token( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::SetDeviceTokenRequest>, + ) -> connectrpc::ServiceResult { + let session_id = ctx.session_id()?; + let req = request.to_owned_message(); + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error in set_device_token"); + ConnectError::internal("database connection error") + })?; + + diesel::update(user_sessions::table.filter(user_sessions::session_id.eq(session_id))) + .set(user_sessions::fcm_token.eq(Some(req.fcm_token))) + .execute(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to update fcm token"); + ConnectError::internal("failed to set device token") + })?; + + Ok(connectrpc::Response::new(p::SetDeviceTokenResponse::default())) + } +} diff --git a/backend/src/services/v1/books.rs b/backend/src/services/v1/books.rs new file mode 100644 index 0000000..8ab30d7 --- /dev/null +++ b/backend/src/services/v1/books.rs @@ -0,0 +1,568 @@ +use super::helpers::{ + book_condition_from_proto, book_condition_to_proto, book_picture_type_from_proto, + book_picture_type_to_proto, book_status_from_proto, book_status_to_proto, lat_lng_to_h3_indices, + user_to_summary, +}; +use super::proto as p; +use crate::db::Database; +use crate::middleware::AuthContextExt; +use crate::models::{ + Book, BookCategory, BookPicture, BookStatus, IndexedLocation, + LocationType, NewBook, NewBookPicture, NewIndexedLocation, UpdateBook, Upload, User, +}; +use crate::schema::{ + book_categories, book_pictures, books, indexed_locations, uploads, users, +}; +use crate::utils::dt_to_proto; +use chrono::{Duration, Utc}; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct BookService { + db: Arc, +} + +impl BookService { + pub fn new(db: Arc) -> Self { + Self { db } + } + + fn load_full_book( + &self, + conn: &mut crate::db::PgPooledConnection, + book: Book, + ) -> Result { + let seller: User = users::table + .find(book.seller_id) + .first(conn) + .map_err(|_| ConnectError::not_found("seller not found"))?; + + let seller_avatar = if let Some(avatar_id) = seller.avatar_id { + uploads::table + .find(avatar_id) + .select(uploads::storage_key) + .first::(conn) + .ok() + } else { + None + }; + + let category: BookCategory = book_categories::table + .find(book.category) + .first(conn) + .unwrap_or(BookCategory { + id: book.category, + name: "General".to_string(), + }); + + let pictures: Vec<(BookPicture, Upload)> = book_pictures::table + .filter(book_pictures::book_id.eq(book.id)) + .inner_join(uploads::table.on(book_pictures::upload_id.eq(uploads::id))) + .load::<(BookPicture, Upload)>(conn) + .unwrap_or_default(); + + let proto_pictures = pictures + .into_iter() + .map(|(bp, up)| p::BookPicture { + upload_id: bp.upload_id.to_string(), + url: up.storage_key, + r#type: book_picture_type_to_proto(bp.type_).into(), + ..Default::default() + }) + .collect(); + + let location = if let Some(loc_id) = book.location { + indexed_locations::table + .find(loc_id) + .first::(conn) + .ok() + .map(|loc| p::LatLng { + latitude: loc.latitude, + longitude: loc.longitude, + ..Default::default() + }) + } else { + None + }; + + Ok(p::Book { + id: book.id.to_string(), + seller: Some(user_to_summary(seller, seller_avatar)).into(), + title: book.title, + author: book.author, + price_fcfa: book.price as i64, + condition: book_condition_to_proto(book.condition).into(), + description: book.description.unwrap_or_default(), + status: book_status_to_proto(book.status).into(), + category: Some(p::BookCategory { + id: category.id, + name: category.name, + ..Default::default() + }) + .into(), + refundable: book.refundable, + swapable: book.swapable, + pictures: proto_pictures, + ebook_id: book.ebook_id.map(|id| id.to_string()).unwrap_or_default(), + boost_expires_at: Some(dt_to_proto(book.boost_expires_at)).into(), + expires_at: Some(dt_to_proto(book.expires_at)).into(), + created_at: Some(dt_to_proto(book.created_at)).into(), + updated_at: Some(dt_to_proto(book.updated_at)).into(), + location: location.into(), + ..Default::default() + }) + } +} + +impl p::BookService for BookService { + async fn list_categories( + &self, + _ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::ListCategoriesRequest>, + ) -> connectrpc::ServiceResult { + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let cats: Vec = book_categories::table + .order(book_categories::name.asc()) + .load(&mut conn) + .unwrap_or_default(); + + let proto_cats = cats + .into_iter() + .map(|c| p::BookCategory { + id: c.id, + name: c.name, + ..Default::default() + }) + .collect(); + + Ok(connectrpc::Response::new(p::ListCategoriesResponse { + categories: proto_cats, + ..Default::default() + })) + } + + async fn list_books( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::ListBooksRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let mut query = books::table + .filter(books::deleted_at.is_null()) + .into_boxed(); + + let status = req.status.as_known(); + if let Some(s) = status { + if s != p::BookStatus::BOOK_STATUS_UNSPECIFIED { + query = query.filter(books::status.eq(book_status_from_proto(s))); + } + } else { + query = query.filter(books::status.eq(BookStatus::Available)); + } + + if req.category_id > 0 { + query = query.filter(books::category.eq(req.category_id)); + } + + let limit = if req.page_size > 0 && req.page_size <= 100 { + req.page_size as i64 + } else { + 50 + }; + + let items: Vec = query + .order((books::boost_expires_at.desc(), books::created_at.desc())) + .limit(limit) + .load(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to load books"); + ConnectError::internal("failed to query books") + })?; + + let mut proto_books = Vec::new(); + for b in items { + if let Ok(pb) = self.load_full_book(&mut conn, b) { + proto_books.push(pb); + } + } + + Ok(connectrpc::Response::new(p::ListBooksResponse { + books: proto_books, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn search_books( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::SearchBooksRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let search_pattern = format!("%{}%", req.query.trim()); + let mut query = books::table + .filter(books::deleted_at.is_null()) + .filter(books::status.eq(BookStatus::Available)) + .filter(books::title.ilike(search_pattern.clone()).or(books::author.ilike(search_pattern))) + .into_boxed(); + + if req.category_id > 0 { + query = query.filter(books::category.eq(req.category_id)); + } + + let limit = if req.page_size > 0 && req.page_size <= 100 { + req.page_size as i64 + } else { + 50 + }; + + let items: Vec = query + .order(books::created_at.desc()) + .limit(limit) + .load(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to search books"); + ConnectError::internal("failed to search books") + })?; + + let mut proto_books = Vec::new(); + for b in items { + if let Ok(pb) = self.load_full_book(&mut conn, b) { + proto_books.push(pb); + } + } + + Ok(connectrpc::Response::new(p::SearchBooksResponse { + books: proto_books, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn get_book( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::GetBookRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let book: Book = books::table + .find(book_id) + .filter(books::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("book not found"))?; + + let proto_book = self.load_full_book(&mut conn, book)?; + Ok(connectrpc::Response::new(p::GetBookResponse { + book: Some(proto_book).into(), + ..Default::default() + })) + } + + async fn list_books_by_seller( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::ListBooksBySellerRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let seller_id = Uuid::parse_str(&req.seller_id) + .map_err(|_| ConnectError::invalid_argument("invalid seller ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let items: Vec = books::table + .filter(books::seller_id.eq(seller_id)) + .filter(books::deleted_at.is_null()) + .order(books::created_at.desc()) + .load(&mut conn) + .map_err(|_| ConnectError::internal("failed to load books"))?; + + let mut proto_books = Vec::new(); + for b in items { + if let Ok(pb) = self.load_full_book(&mut conn, b) { + proto_books.push(pb); + } + } + + Ok(connectrpc::Response::new(p::ListBooksBySellerResponse { + books: proto_books, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn list_my_books( + &self, + ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::ListMyBooksRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let items: Vec = books::table + .filter(books::seller_id.eq(user_id)) + .filter(books::deleted_at.is_null()) + .order(books::created_at.desc()) + .load(&mut conn) + .map_err(|_| ConnectError::internal("failed to load user books"))?; + + let mut proto_books = Vec::new(); + for b in items { + if let Ok(pb) = self.load_full_book(&mut conn, b) { + proto_books.push(pb); + } + } + + Ok(connectrpc::Response::new(p::ListMyBooksResponse { + books: proto_books, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn create_book( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::CreateBookRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + + if req.title.trim().is_empty() || req.author.trim().is_empty() { + return Err(ConnectError::invalid_argument("title and author are required")); + } + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let book_id = Uuid::now_v7(); + let expires_days = req.expires_in_days.unwrap_or(60); + let expires_at = Utc::now() + Duration::days(expires_days as i64); + + let location_id = if let Some(loc) = req.location.as_option() { + if let Ok((h3_3, h3_4, h3_5, h3_6, h3_7)) = + lat_lng_to_h3_indices(loc.latitude, loc.longitude) + { + let loc_id = Uuid::now_v7(); + let new_loc = NewIndexedLocation { + id: loc_id, + type_: LocationType::Book, + latitude: loc.latitude, + longitude: loc.longitude, + h3_3, + h3_4, + h3_5, + h3_6, + h3_7, + }; + diesel::insert_into(indexed_locations::table) + .values(&new_loc) + .execute(&mut conn) + .ok(); + Some(loc_id) + } else { + None + } + } else { + None + }; + + let ebook_uuid = if !req.ebook_upload_id.is_empty() { + Uuid::parse_str(&req.ebook_upload_id).ok() + } else { + None + }; + + let new_book = NewBook { + id: book_id, + seller_id: user_id, + ebook_id: ebook_uuid, + title: req.title.trim().to_string(), + author: req.author.trim().to_string(), + price: req.price_fcfa as i32, + condition: book_condition_from_proto(req.condition.as_known().unwrap_or(p::BookCondition::BOOK_CONDITION_GOOD)), + description: if req.description.trim().is_empty() { + None + } else { + Some(req.description.trim().to_string()) + }, + status: BookStatus::Available, + category: if req.category_id > 0 { req.category_id } else { 1 }, + refundable: req.refundable, + swapable: req.swapable, + expires_at, + location: location_id, + }; + + let created_book: Book = diesel::insert_into(books::table) + .values(&new_book) + .get_result(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create book"); + ConnectError::internal("failed to create book") + })?; + + for pic_upload_str in req.picture_upload_ids { + if let Ok(pic_upload_id) = Uuid::parse_str(&pic_upload_str) { + let p_type = req + .picture_types + .get(&pic_upload_str) + .copied() + .and_then(|v| v.as_known()) + .unwrap_or(p::BookPictureType::BOOK_PICTURE_TYPE_OTHER); + + let new_pic = NewBookPicture { + book_id, + upload_id: pic_upload_id, + type_: book_picture_type_from_proto(p_type), + }; + let _ = diesel::insert_into(book_pictures::table) + .values(&new_pic) + .execute(&mut conn); + } + } + + let proto_book = self.load_full_book(&mut conn, created_book)?; + Ok(connectrpc::Response::new(p::CreateBookResponse { + book: Some(proto_book).into(), + ..Default::default() + })) + } + + async fn update_book( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::UpdateBookRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let book: Book = books::table + .find(book_id) + .filter(books::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("book not found"))?; + + if book.seller_id != user_id { + return Err(ConnectError::permission_denied("cannot edit another seller's book")); + } + + let mut changeset = UpdateBook::default(); + if let Some(t) = req.title { + changeset.title = Some(t.trim().to_string()); + } + if let Some(a) = req.author { + changeset.author = Some(a.trim().to_string()); + } + if let Some(price) = req.price_fcfa { + changeset.price = Some(price as i32); + } + if let Some(cond) = req.condition { + if let Some(c) = cond.as_known() { + changeset.condition = Some(book_condition_from_proto(c)); + } + } + if let Some(desc) = req.description { + changeset.description = Some(Some(desc.trim().to_string())); + } + if let Some(cat) = req.category_id { + changeset.category = Some(cat); + } + if let Some(status) = req.status { + if let Some(s) = status.as_known() { + changeset.status = Some(book_status_from_proto(s)); + } + } + changeset.refundable = req.refundable; + changeset.swapable = req.swapable; + changeset.updated_at = Some(Utc::now()); + + let updated_book: Book = diesel::update(books::table.find(book_id)) + .set(&changeset) + .get_result(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to update book"); + ConnectError::internal("failed to update book") + })?; + + let proto_book = self.load_full_book(&mut conn, updated_book)?; + Ok(connectrpc::Response::new(p::UpdateBookResponse { + book: Some(proto_book).into(), + ..Default::default() + })) + } + + async fn delete_book( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::DeleteBookRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let book: Book = books::table + .find(book_id) + .filter(books::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("book not found"))?; + + if book.seller_id != user_id { + return Err(ConnectError::permission_denied("cannot delete another seller's book")); + } + + diesel::update(books::table.find(book_id)) + .set(books::deleted_at.eq(Some(Utc::now()))) + .execute(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to delete book"); + ConnectError::internal("failed to delete book") + })?; + + Ok(connectrpc::Response::new(p::DeleteBookResponse::default())) + } +} diff --git a/backend/src/services/v1/boosts.rs b/backend/src/services/v1/boosts.rs new file mode 100644 index 0000000..a6b9a2b --- /dev/null +++ b/backend/src/services/v1/boosts.rs @@ -0,0 +1,291 @@ +use super::proto as p; +use crate::db::Database; +use crate::fapshi::{DirectPayRequest, Fapshi}; +use crate::middleware::AuthContextExt; +use crate::models::{ + Book, Boost, NewBoost, NewDonation, NewPayment, NewPaymentIntent, + PaymentIntent, PaymentMethod, PaymentStatus, User, +}; +use crate::schema::{books, boosts, donations, payment_intents, payments, users}; +use crate::utils::dt_to_proto; +use chrono::{Duration, Utc}; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct BoostService { + db: Arc, + fapshi: Arc, +} + +impl BoostService { + pub fn new(db: Arc, fapshi: Arc) -> Self { + Self { db, fapshi } + } +} + +impl p::BoostService for BoostService { + async fn create_boost( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::CreateBoostRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let book: Book = books::table + .find(book_id) + .filter(books::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("book not found"))?; + + if book.seller_id != user_id { + return Err(ConnectError::permission_denied("can only boost your own book")); + } + + let user: User = users::table.find(user_id).first(&mut conn).map_err(|_| { + ConnectError::not_found("user not found") + })?; + + let intent_id = Uuid::now_v7(); + let new_intent = NewPaymentIntent { + id: intent_id, + user_id, + method: PaymentMethod::Fapshi, + amount: req.amount_fcfa as i32, + status: PaymentStatus::Pending, + }; + + diesel::insert_into(payment_intents::table) + .values(&new_intent) + .execute(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create payment intent"); + ConnectError::internal("payment intent creation failed") + })?; + + let fapshi_payload = DirectPayRequest { + amount: req.amount_fcfa as u64, + phone: &user.phone, + network: None, + name: Some(&user.first_name), + email: user.email.as_deref(), + user_id: Some(&user.id.to_string()), + trans_id: Some(&intent_id.to_string()), + reason: Some("Book promotion boost"), + }; + + let fapshi_res = self.fapshi.direct_pay(&fapshi_payload).await.map_err(|err| { + tracing::error!(%err, "Fapshi payment request failed"); + ConnectError::internal("payment gateway error") + })?; + + let external_ref = fapshi_res.trans_id.unwrap_or_else(|| intent_id.to_string()); + let new_payment = NewPayment { + intent_id, + platform_transaction_reference: external_ref.clone(), + }; + + diesel::insert_into(payments::table) + .values(&new_payment) + .execute(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create payment record"); + ConnectError::internal("payment record creation failed") + })?; + + let expires_at = Utc::now() + Duration::days(7); + let new_boost = NewBoost { + payment_id: intent_id, + book_id, + expires_at, + }; + + diesel::insert_into(boosts::table) + .values(&new_boost) + .execute(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create boost record"); + ConnectError::internal("boost creation failed") + })?; + + // Update book boost expiry + let _ = diesel::update(books::table.find(book_id)) + .set(books::boost_expires_at.eq(expires_at)) + .execute(&mut conn); + + let proto_boost = p::Boost { + id: intent_id.to_string(), + book_id: book_id.to_string(), + amount_fcfa: req.amount_fcfa, + expires_at: Some(dt_to_proto(expires_at)).into(), + created_at: Some(dt_to_proto(Utc::now())).into(), + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::CreateBoostResponse { + boost: Some(proto_boost).into(), + fapshi_transaction_id: external_ref, + ..Default::default() + })) + } + + async fn get_boost_status( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::GetBoostStatusRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let boost_id = Uuid::parse_str(&req.boost_id) + .map_err(|_| ConnectError::invalid_argument("invalid boost ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let boost: Boost = boosts::table + .find(boost_id) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("boost not found"))?; + + let intent: PaymentIntent = payment_intents::table + .find(boost.payment_id) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("payment not found"))?; + + let proto_boost = p::Boost { + id: boost.payment_id.to_string(), + book_id: boost.book_id.to_string(), + amount_fcfa: intent.amount as i64, + expires_at: Some(dt_to_proto(boost.expires_at)).into(), + created_at: Some(dt_to_proto(boost.created_at)).into(), + ..Default::default() + }; + + let outcome = p::PaymentOutcome { + status: format!("{:?}", intent.status), + message: if boost.expires_at > Utc::now() && intent.status == PaymentStatus::Completed { + "active".to_string() + } else { + "inactive".to_string() + }, + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::GetBoostStatusResponse { + boost: Some(proto_boost).into(), + outcome: Some(outcome).into(), + ..Default::default() + })) + } +} + +pub struct DonationService { + db: Arc, + fapshi: Arc, +} + +impl DonationService { + pub fn new(db: Arc, fapshi: Arc) -> Self { + Self { db, fapshi } + } +} + +impl p::DonationService for DonationService { + async fn create_donation( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::CreateDonationRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id().ok(); + let req = request.to_owned_message(); + + if req.amount_fcfa <= 0 { + return Err(ConnectError::invalid_argument("donation amount must be greater than 0")); + } + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let donor_phone = if let Some(uid) = user_id { + users::table + .find(uid) + .select(users::phone) + .first::(&mut conn) + .unwrap_or_else(|_| "+237600000000".to_string()) + } else { + "+237600000000".to_string() + }; + + let intent_id = Uuid::now_v7(); + let new_intent = NewPaymentIntent { + id: intent_id, + user_id: user_id.unwrap_or_else(Uuid::now_v7), + method: PaymentMethod::Fapshi, + amount: req.amount_fcfa as i32, + status: PaymentStatus::Pending, + }; + + let _ = diesel::insert_into(payment_intents::table) + .values(&new_intent) + .execute(&mut conn); + + let fapshi_payload = DirectPayRequest { + amount: req.amount_fcfa as u64, + phone: &donor_phone, + network: None, + name: Some("BookBridge Supporter"), + email: None, + user_id: None, + trans_id: Some(&intent_id.to_string()), + reason: Some("Platform Donation"), + }; + + let external_ref = match self.fapshi.direct_pay(&fapshi_payload).await { + Ok(r) => r.trans_id.unwrap_or_else(|| intent_id.to_string()), + Err(_) => intent_id.to_string(), + }; + + let new_payment = NewPayment { + intent_id, + platform_transaction_reference: external_ref.clone(), + }; + let _ = diesel::insert_into(payments::table).values(&new_payment).execute(&mut conn); + + let new_donation = NewDonation { + payment_id: intent_id, + user_id, + message: if req.message.trim().is_empty() { + None + } else { + Some(req.message.trim().to_string()) + }, + }; + let _ = diesel::insert_into(donations::table).values(&new_donation).execute(&mut conn); + + let proto_donation = p::Donation { + id: intent_id.to_string(), + amount_fcfa: req.amount_fcfa, + message: req.message.trim().to_string(), + created_at: Some(dt_to_proto(Utc::now())).into(), + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::CreateDonationResponse { + donation: Some(proto_donation).into(), + fapshi_transaction_id: external_ref, + ..Default::default() + })) + } +} diff --git a/backend/src/services/v1/chat.rs b/backend/src/services/v1/chat.rs new file mode 100644 index 0000000..a633495 --- /dev/null +++ b/backend/src/services/v1/chat.rs @@ -0,0 +1,330 @@ +use super::helpers::user_to_summary; +use super::proto as p; +use crate::db::Database; +use crate::middleware::AuthContextExt; +use crate::models::{Book, Conversation, ConversationMessage, NewConversation, NewConversationMessage, Upload, User}; +use crate::schema::{books, conversation_messages, conversations, uploads, users}; +use crate::utils::dt_to_proto; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct ChatService { + db: Arc, +} + +impl ChatService { + pub fn new(db: Arc) -> Self { + Self { db } + } + + fn message_to_proto( + &self, + conn: &mut crate::db::PgPooledConnection, + m: ConversationMessage, + ) -> p::Message { + let attachment = if let Some(att_id) = m.attachment { + if let Ok(u) = uploads::table.find(att_id).first::(conn) { + Some(p::UploadAttachment { + upload_id: u.id.to_string(), + url: u.storage_key, + content_type: u.content_type, + file_name: u.file_name, + ..Default::default() + }) + } else { + None + } + } else { + None + }; + + p::Message { + id: m.id.to_string(), + conversation_id: m.conversation_id.to_string(), + user_id: m.user_id.to_string(), + content: m.content, + attachment: attachment.into(), + created_at: Some(dt_to_proto(m.created_at)).into(), + ..Default::default() + } + } +} + +impl p::ChatService for ChatService { + async fn list_conversations( + &self, + ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::ListConversationsRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let convs: Vec = conversations::table + .filter(conversations::deleted_at.is_null()) + .filter(conversations::user_id.eq(user_id)) + .order(conversations::created_at.desc()) + .load(&mut conn) + .map_err(|_| ConnectError::internal("failed to load conversations"))?; + + let mut proto_convs = Vec::new(); + for c in convs { + let book: Option = books::table.find(c.book_id).first(&mut conn).ok(); + let other_user_id = if let Some(ref b) = book { + if b.seller_id == user_id { + c.user_id + } else { + b.seller_id + } + } else { + c.user_id + }; + + let other_user = users::table.find(other_user_id).first::(&mut conn).ok(); + let other_avatar = if let Some(ref u) = other_user { + if let Some(av_id) = u.avatar_id { + uploads::table + .find(av_id) + .select(uploads::storage_key) + .first::(&mut conn) + .ok() + } else { + None + } + } else { + None + }; + + let last_msg: Option = conversation_messages::table + .filter(conversation_messages::conversation_id.eq(c.id)) + .order(conversation_messages::created_at.desc()) + .first(&mut conn) + .ok(); + + let (last_message, last_message_at) = if let Some(m) = last_msg { + (m.content, Some(dt_to_proto(m.created_at))) + } else { + (String::new(), None) + }; + + let book_summary = book.map(|b| p::BookSummary { + id: b.id.to_string(), + title: b.title, + cover_url: String::new(), + ..Default::default() + }); + + let other_participant = other_user.map(|u| user_to_summary(u, other_avatar)); + + proto_convs.push(p::Conversation { + id: c.id.to_string(), + book_id: c.book_id.to_string(), + book: book_summary.into(), + other_participant: other_participant.into(), + last_message, + last_message_at: last_message_at.into(), + unread_count: 0, + ..Default::default() + }); + } + + Ok(connectrpc::Response::new(p::ListConversationsResponse { + conversations: proto_convs, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn get_or_create_conversation( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::GetOrCreateConversationRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let existing: Option = conversations::table + .filter(conversations::book_id.eq(book_id)) + .filter(conversations::user_id.eq(user_id)) + .filter(conversations::deleted_at.is_null()) + .first(&mut conn) + .ok(); + + let conv = match existing { + Some(c) => c, + None => { + let new_id = Uuid::now_v7(); + let new_c = NewConversation { + id: new_id, + book_id, + user_id, + }; + diesel::insert_into(conversations::table) + .values(&new_c) + .get_result(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create conversation"); + ConnectError::internal("failed to create conversation") + })? + } + }; + + let book: Option = books::table.find(conv.book_id).first(&mut conn).ok(); + let seller_id = book.as_ref().map(|b| b.seller_id).unwrap_or(user_id); + let other_user = users::table.find(seller_id).first::(&mut conn).ok(); + let other_avatar = if let Some(ref u) = other_user { + if let Some(av_id) = u.avatar_id { + uploads::table + .find(av_id) + .select(uploads::storage_key) + .first::(&mut conn) + .ok() + } else { + None + } + } else { + None + }; + + let proto_conv = p::Conversation { + id: conv.id.to_string(), + book_id: conv.book_id.to_string(), + book: book.map(|b| p::BookSummary { + id: b.id.to_string(), + title: b.title, + cover_url: String::new(), + ..Default::default() + }).into(), + other_participant: other_user.map(|u| user_to_summary(u, other_avatar)).into(), + last_message: String::new(), + last_message_at: None.into(), + unread_count: 0, + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::GetOrCreateConversationResponse { + conversation: Some(proto_conv).into(), + ..Default::default() + })) + } + + async fn list_messages( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::ListMessagesRequest>, + ) -> connectrpc::ServiceResult { + let _user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let conv_id = Uuid::parse_str(&req.conversation_id) + .map_err(|_| ConnectError::invalid_argument("invalid conversation ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let messages: Vec = conversation_messages::table + .filter(conversation_messages::conversation_id.eq(conv_id)) + .filter(conversation_messages::deleted_at.is_null()) + .order(conversation_messages::created_at.asc()) + .limit(100) + .load(&mut conn) + .map_err(|_| ConnectError::internal("failed to load messages"))?; + + let proto_messages: Vec = messages + .into_iter() + .map(|m| self.message_to_proto(&mut conn, m)) + .collect(); + + Ok(connectrpc::Response::new(p::ListMessagesResponse { + messages: proto_messages, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn send_message( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::SendMessageRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let conv_id = Uuid::parse_str(&req.conversation_id) + .map_err(|_| ConnectError::invalid_argument("invalid conversation ID format"))?; + + if req.content.trim().is_empty() && req.attachment_upload_id.trim().is_empty() { + return Err(ConnectError::invalid_argument("message content or attachment is required")); + } + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let attachment_id = if !req.attachment_upload_id.trim().is_empty() { + Uuid::parse_str(&req.attachment_upload_id).ok() + } else { + None + }; + + let msg_id = Uuid::now_v7(); + let new_msg = NewConversationMessage { + id: msg_id, + user_id, + conversation_id: conv_id, + content: req.content.trim().to_string(), + attachment: attachment_id, + }; + + let msg: ConversationMessage = diesel::insert_into(conversation_messages::table) + .values(&new_msg) + .get_result(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to insert message"); + ConnectError::internal("failed to send message") + })?; + + let proto_msg = self.message_to_proto(&mut conn, msg); + Ok(connectrpc::Response::new(p::SendMessageResponse { + message: Some(proto_msg).into(), + ..Default::default() + })) + } + + async fn mark_messages_read( + &self, + _ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::MarkMessagesReadRequest>, + ) -> connectrpc::ServiceResult { + Ok(connectrpc::Response::new(p::MarkMessagesReadResponse::default())) + } + + async fn stream_conversations( + &self, + _ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::StreamConversationsRequest>, + ) -> connectrpc::ServiceResult> { + let stream = async_stream::stream! { + yield Ok::<_, ConnectError>(p::StreamConversationsResponse { + ..Default::default() + }); + loop { + tokio::time::sleep(std::time::Duration::from_secs(30)).await; + } + }; + + Ok(connectrpc::Response::new(Box::pin(stream))) + } +} diff --git a/backend/src/services/v1/helpers.rs b/backend/src/services/v1/helpers.rs new file mode 100644 index 0000000..d4ff110 --- /dev/null +++ b/backend/src/services/v1/helpers.rs @@ -0,0 +1,108 @@ +use super::proto as p; +use crate::models::{self, BookCondition, BookPictureType, BookStatus}; +use crate::utils::dt_to_proto; +use connectrpc::error::ConnectError; + +pub fn user_to_proto(user: models::User, avatar_url: Option) -> p::User { + p::User { + id: user.id.to_string(), + email: user.email.unwrap_or_default(), + phone: user.phone, + first_name: user.first_name, + last_name: user.last_name, + avatar_url: avatar_url.unwrap_or_default(), + rating: user.rating.to_string().parse().unwrap_or(0.0), + verified: user.verified, + created_at: Some(dt_to_proto(user.created_at)).into(), + updated_at: Some(dt_to_proto(user.updated_at)).into(), + ..Default::default() + } +} + +pub fn user_to_summary(user: models::User, avatar_url: Option) -> p::UserSummary { + p::UserSummary { + id: user.id.to_string(), + first_name: user.first_name, + last_name: user.last_name, + avatar_url: avatar_url.unwrap_or_default(), + rating: user.rating.to_string().parse().unwrap_or(0.0), + verified: user.verified, + ..Default::default() + } +} + +pub fn book_condition_to_proto(c: BookCondition) -> p::BookCondition { + match c { + BookCondition::New => p::BookCondition::BOOK_CONDITION_NEW, + BookCondition::LikeNew => p::BookCondition::BOOK_CONDITION_LIKE_NEW, + BookCondition::Good => p::BookCondition::BOOK_CONDITION_GOOD, + BookCondition::Fair => p::BookCondition::BOOK_CONDITION_FAIR, + BookCondition::Poor => p::BookCondition::BOOK_CONDITION_POOR, + } +} + +pub fn book_condition_from_proto(c: p::BookCondition) -> BookCondition { + match c { + p::BookCondition::BOOK_CONDITION_NEW => BookCondition::New, + p::BookCondition::BOOK_CONDITION_LIKE_NEW => BookCondition::LikeNew, + p::BookCondition::BOOK_CONDITION_GOOD => BookCondition::Good, + p::BookCondition::BOOK_CONDITION_FAIR => BookCondition::Fair, + p::BookCondition::BOOK_CONDITION_POOR => BookCondition::Poor, + _ => BookCondition::Good, + } +} + +pub fn book_status_to_proto(s: BookStatus) -> p::BookStatus { + match s { + BookStatus::Available => p::BookStatus::BOOK_STATUS_AVAILABLE, + BookStatus::Sold => p::BookStatus::BOOK_STATUS_SOLD, + BookStatus::Reserved => p::BookStatus::BOOK_STATUS_RESERVED, + BookStatus::Expired => p::BookStatus::BOOK_STATUS_EXPIRED, + BookStatus::Removed => p::BookStatus::BOOK_STATUS_REMOVED, + } +} + +pub fn book_status_from_proto(s: p::BookStatus) -> BookStatus { + match s { + p::BookStatus::BOOK_STATUS_AVAILABLE => BookStatus::Available, + p::BookStatus::BOOK_STATUS_SOLD => BookStatus::Sold, + p::BookStatus::BOOK_STATUS_RESERVED => BookStatus::Reserved, + p::BookStatus::BOOK_STATUS_EXPIRED => BookStatus::Expired, + p::BookStatus::BOOK_STATUS_REMOVED => BookStatus::Removed, + _ => BookStatus::Available, + } +} + +pub fn book_picture_type_to_proto(t: BookPictureType) -> p::BookPictureType { + match t { + BookPictureType::Front => p::BookPictureType::BOOK_PICTURE_TYPE_FRONT, + BookPictureType::Back => p::BookPictureType::BOOK_PICTURE_TYPE_BACK, + BookPictureType::Other => p::BookPictureType::BOOK_PICTURE_TYPE_OTHER, + } +} + +pub fn book_picture_type_from_proto(t: p::BookPictureType) -> BookPictureType { + match t { + p::BookPictureType::BOOK_PICTURE_TYPE_FRONT => BookPictureType::Front, + p::BookPictureType::BOOK_PICTURE_TYPE_BACK => BookPictureType::Back, + _ => BookPictureType::Other, + } +} + +pub fn lat_lng_to_h3_indices( + latitude: f64, + longitude: f64, +) -> Result<(i64, i64, i64, i64, i64), ConnectError> { + let coord = h3o::LatLng::new(latitude, longitude).map_err(|err| { + tracing::warn!(%latitude, %longitude, %err, "Invalid geographic coordinates"); + ConnectError::invalid_argument(format!("invalid latitude/longitude coordinates: {err}")) + })?; + + let h3_3 = u64::from(coord.to_cell(h3o::Resolution::Three)) as i64; + let h3_4 = u64::from(coord.to_cell(h3o::Resolution::Four)) as i64; + let h3_5 = u64::from(coord.to_cell(h3o::Resolution::Five)) as i64; + let h3_6 = u64::from(coord.to_cell(h3o::Resolution::Six)) as i64; + let h3_7 = u64::from(coord.to_cell(h3o::Resolution::Seven)) as i64; + + Ok((h3_3, h3_4, h3_5, h3_6, h3_7)) +} diff --git a/backend/src/services/v1/locations.rs b/backend/src/services/v1/locations.rs new file mode 100644 index 0000000..5ffcab0 --- /dev/null +++ b/backend/src/services/v1/locations.rs @@ -0,0 +1,108 @@ +use super::proto as p; +use crate::db::Database; +use crate::models::{IndexedLocation, MeetupLocation}; +use crate::schema::{indexed_locations, meetup_locations}; +use crate::utils::dt_to_proto; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct MeetupLocationService { + db: Arc, +} + +impl MeetupLocationService { + pub fn new(db: Arc) -> Self { + Self { db } + } +} + +impl p::MeetupLocationService for MeetupLocationService { + async fn list_meetup_locations( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::ListMeetupLocationsRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let limit = if req.page_size > 0 && req.page_size <= 100 { + req.page_size as i64 + } else { + 50 + }; + + let items: Vec<(MeetupLocation, IndexedLocation)> = meetup_locations::table + .inner_join(indexed_locations::table.on(meetup_locations::location_id.eq(indexed_locations::id))) + .limit(limit) + .load(&mut conn) + .unwrap_or_default(); + + let proto_locations = items + .into_iter() + .map(|(ml, il)| p::MeetupLocation { + id: ml.id.to_string(), + name: ml.name, + description: ml.description.unwrap_or_default(), + verified: ml.verified, + location: Some(p::LatLng { + latitude: il.latitude, + longitude: il.longitude, + ..Default::default() + }).into(), + created_at: Some(dt_to_proto(ml.created_at)).into(), + ..Default::default() + }) + .collect(); + + Ok(connectrpc::Response::new(p::ListMeetupLocationsResponse { + locations: proto_locations, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn get_meetup_location( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::GetMeetupLocationRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let location_id = Uuid::parse_str(&req.location_id) + .map_err(|_| ConnectError::invalid_argument("invalid location ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let (ml, il): (MeetupLocation, IndexedLocation) = meetup_locations::table + .find(location_id) + .inner_join(indexed_locations::table.on(meetup_locations::location_id.eq(indexed_locations::id))) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("meetup location not found"))?; + + let proto_location = p::MeetupLocation { + id: ml.id.to_string(), + name: ml.name, + description: ml.description.unwrap_or_default(), + verified: ml.verified, + location: Some(p::LatLng { + latitude: il.latitude, + longitude: il.longitude, + ..Default::default() + }).into(), + created_at: Some(dt_to_proto(ml.created_at)).into(), + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::GetMeetupLocationResponse { + location: Some(proto_location).into(), + ..Default::default() + })) + } +} diff --git a/backend/src/services/v1/mod.rs b/backend/src/services/v1/mod.rs new file mode 100644 index 0000000..23b5be1 --- /dev/null +++ b/backend/src/services/v1/mod.rs @@ -0,0 +1,39 @@ +pub use connectrpc::Router; +pub use std::sync::Arc; + +pub mod auth; +pub mod books; +pub mod boosts; +pub mod chat; +pub mod helpers; +pub mod locations; +pub mod notifications; +pub mod proto; +pub mod purchases; +pub mod reviews; +pub mod stats; +pub mod uploads; +pub mod users; +pub mod wishlist; + +pub fn include( + router: Router, + db: Arc, + jwt: Arc, + fapshi: Arc, +) -> Router { + router + .add_service(Arc::new(auth::AuthService::new(db.clone(), jwt.clone()))) + .add_service(Arc::new(books::BookService::new(db.clone()))) + .add_service(Arc::new(boosts::BoostService::new(db.clone(), fapshi.clone()))) + .add_service(Arc::new(boosts::DonationService::new(db.clone(), fapshi.clone()))) + .add_service(Arc::new(chat::ChatService::new(db.clone()))) + .add_service(Arc::new(locations::MeetupLocationService::new(db.clone()))) + .add_service(Arc::new(notifications::NotificationService::new(db.clone()))) + .add_service(Arc::new(purchases::PurchaseService::new(db.clone(), fapshi.clone()))) + .add_service(Arc::new(reviews::ReviewService::new(db.clone()))) + .add_service(Arc::new(stats::StatsService::new(db.clone()))) + .add_service(Arc::new(uploads::UploadService::new(db.clone()))) + .add_service(Arc::new(users::UserService::new(db.clone()))) + .add_service(Arc::new(wishlist::WishlistService::new(db.clone()))) +} diff --git a/backend/src/services/v1/notifications.rs b/backend/src/services/v1/notifications.rs new file mode 100644 index 0000000..22b9087 --- /dev/null +++ b/backend/src/services/v1/notifications.rs @@ -0,0 +1,141 @@ +use super::proto as p; +use crate::db::Database; +use crate::middleware::AuthContextExt; +use crate::models::Notification; +use crate::schema::notifications; +use crate::utils::{dt_to_proto, opt_dt_to_proto}; +use chrono::Utc; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct NotificationService { + db: Arc, +} + +impl NotificationService { + pub fn new(db: Arc) -> Self { + Self { db } + } +} + +impl p::NotificationService for NotificationService { + async fn list_notifications( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::ListNotificationsRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let mut query = notifications::table + .filter(notifications::user_id.eq(user_id)) + .into_boxed(); + + if req.unread_only { + query = query.filter(notifications::read_at.is_null()); + } + + let limit = if req.page_size > 0 && req.page_size <= 100 { + req.page_size as i64 + } else { + 50 + }; + + let items: Vec = query + .order(notifications::created_at.desc()) + .limit(limit) + .load(&mut conn) + .unwrap_or_default(); + + let proto_notifs = items + .into_iter() + .map(|n| p::Notification { + id: n.id.to_string(), + title: "BookBridge Notification".to_string(), + body: String::new(), + r#type: "general".to_string(), + read_at: opt_dt_to_proto(n.read_at), + created_at: Some(dt_to_proto(n.created_at)).into(), + ..Default::default() + }) + .collect(); + + Ok(connectrpc::Response::new(p::ListNotificationsResponse { + notifications: proto_notifs, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn mark_notification_read( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::MarkNotificationReadRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let notif_id = Uuid::parse_str(&req.notification_id) + .map_err(|_| ConnectError::invalid_argument("invalid notification ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let _ = diesel::update( + notifications::table + .find(notif_id) + .filter(notifications::user_id.eq(user_id)), + ) + .set(notifications::read_at.eq(Some(Utc::now()))) + .execute(&mut conn); + + Ok(connectrpc::Response::new(p::MarkNotificationReadResponse::default())) + } + + async fn mark_all_notifications_read( + &self, + ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::MarkAllNotificationsReadRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let _ = diesel::update( + notifications::table + .filter(notifications::user_id.eq(user_id)) + .filter(notifications::read_at.is_null()), + ) + .set(notifications::read_at.eq(Some(Utc::now()))) + .execute(&mut conn); + + Ok(connectrpc::Response::new(p::MarkAllNotificationsReadResponse::default())) + } + + async fn stream_notifications( + &self, + _ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::StreamNotificationsRequest>, + ) -> connectrpc::ServiceResult> { + let stream = async_stream::stream! { + yield Ok::<_, ConnectError>(p::StreamNotificationsResponse { + ..Default::default() + }); + loop { + tokio::time::sleep(std::time::Duration::from_secs(30)).await; + } + }; + + Ok(connectrpc::Response::new(Box::pin(stream))) + } +} diff --git a/backend/src/services/v1/proto.rs b/backend/src/services/v1/proto.rs new file mode 100644 index 0000000..4e7ee22 --- /dev/null +++ b/backend/src/services/v1/proto.rs @@ -0,0 +1,2 @@ +pub use crate::proto::buf::bookbridge::v1::*; +pub use crate::proto::svc::bookbridge::v1::*; diff --git a/backend/src/services/v1/purchases.rs b/backend/src/services/v1/purchases.rs new file mode 100644 index 0000000..0114ef2 --- /dev/null +++ b/backend/src/services/v1/purchases.rs @@ -0,0 +1,439 @@ +use super::proto as p; +use crate::db::Database; +use crate::fapshi::{DirectPayRequest, Fapshi}; +use crate::middleware::AuthContextExt; +use crate::models::{ + Book, BookPurchase, NewBookPurchase, NewPayment, NewPaymentIntent, NewTransaction, + PaymentIntent, PaymentMethod, PaymentStatus, Transaction, TransactionStatus, User, +}; +use crate::schema::{ + book_purchases, books, payment_intents, payments, transactions, users, +}; +use crate::utils::dt_to_proto; +use chrono::Utc; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct PurchaseService { + db: Arc, + fapshi: Arc, +} + +impl PurchaseService { + pub fn new(db: Arc, fapshi: Arc) -> Self { + Self { db, fapshi } + } + + fn tx_status_to_proto(s: TransactionStatus) -> p::TransactionStatus { + match s { + TransactionStatus::Held => p::TransactionStatus::TRANSACTION_STATUS_HELD, + TransactionStatus::Released => p::TransactionStatus::TRANSACTION_STATUS_RELEASED, + TransactionStatus::Refunded => p::TransactionStatus::TRANSACTION_STATUS_REFUNDED, + TransactionStatus::Disputed => p::TransactionStatus::TRANSACTION_STATUS_DISPUTED, + } + } +} + +impl p::PurchaseService for PurchaseService { + async fn create_book_purchase( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::CreateBookPurchaseRequest>, + ) -> connectrpc::ServiceResult { + let buyer_id = ctx.user_id()?; + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let book: Book = books::table + .find(book_id) + .filter(books::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("book not found"))?; + + let buyer: User = users::table.find(buyer_id).first(&mut conn).map_err(|_| { + ConnectError::not_found("buyer profile not found") + })?; + + let meetup_location_id = req + .meetup_location_id + .as_deref() + .and_then(|id| Uuid::parse_str(id).ok()); + + let intent_id = Uuid::now_v7(); + let new_intent = NewPaymentIntent { + id: intent_id, + user_id: buyer_id, + method: PaymentMethod::Fapshi, + amount: book.price, + status: PaymentStatus::Pending, + }; + + diesel::insert_into(payment_intents::table) + .values(&new_intent) + .execute(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create payment intent"); + ConnectError::internal("failed to create payment intent") + })?; + + let fapshi_payload = DirectPayRequest { + amount: book.price as u64, + phone: &buyer.phone, + network: None, + name: Some(&buyer.first_name), + email: buyer.email.as_deref(), + user_id: Some(&buyer_id.to_string()), + trans_id: Some(&intent_id.to_string()), + reason: Some("BookBridge Purchase"), + }; + + let fapshi_res = self.fapshi.direct_pay(&fapshi_payload).await.map_err(|err| { + tracing::error!(%err, "Fapshi direct-pay failed"); + ConnectError::internal("payment gateway error") + })?; + + let external_ref = fapshi_res.trans_id.unwrap_or_else(|| intent_id.to_string()); + let new_payment = NewPayment { + intent_id, + platform_transaction_reference: external_ref.clone(), + }; + diesel::insert_into(payments::table).values(&new_payment).execute(&mut conn).map_err(|_| { + ConnectError::internal("payment record creation failed") + })?; + + let new_tx = NewTransaction { + payment_id: intent_id, + recipient: book.seller_id, + transaction_status: TransactionStatus::Held, + }; + diesel::insert_into(transactions::table).values(&new_tx).execute(&mut conn).map_err(|_| { + ConnectError::internal("transaction creation failed") + })?; + + let new_purchase = NewBookPurchase { + transaction_id: intent_id, + book_id, + meetup_location: meetup_location_id, + confirmed: false, + }; + diesel::insert_into(book_purchases::table).values(&new_purchase).execute(&mut conn).map_err(|_| { + ConnectError::internal("purchase creation failed") + })?; + + let proto_purchase = p::Purchase { + id: intent_id.to_string(), + transaction_id: intent_id.to_string(), + book: Some(p::BookPurchaseDetails { + book_id: book.id.to_string(), + title: book.title, + cover_url: String::new(), + price_fcfa: book.price as i64, + meetup_location: None.into(), + ..Default::default() + }).into(), + buyer_id: buyer_id.to_string(), + status: p::TransactionStatus::TRANSACTION_STATUS_HELD.into(), + confirmed: false, + created_at: Some(dt_to_proto(Utc::now())).into(), + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::CreateBookPurchaseResponse { + purchase: Some(proto_purchase).into(), + fapshi_transaction_id: external_ref, + ..Default::default() + })) + } + + async fn get_purchase( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::GetPurchaseRequest>, + ) -> connectrpc::ServiceResult { + let _user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let purchase_id = Uuid::parse_str(&req.purchase_id) + .map_err(|_| ConnectError::invalid_argument("invalid purchase ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let purchase: BookPurchase = book_purchases::table + .find(purchase_id) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("purchase not found"))?; + + let tx: Transaction = transactions::table + .find(purchase.transaction_id) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("transaction not found"))?; + + let intent: PaymentIntent = payment_intents::table + .find(purchase.transaction_id) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("payment not found"))?; + + let book: Book = books::table + .find(purchase.book_id) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("book not found"))?; + + let proto_purchase = p::Purchase { + id: purchase.transaction_id.to_string(), + transaction_id: purchase.transaction_id.to_string(), + book: Some(p::BookPurchaseDetails { + book_id: book.id.to_string(), + title: book.title, + cover_url: String::new(), + price_fcfa: book.price as i64, + meetup_location: None.into(), + ..Default::default() + }).into(), + buyer_id: intent.user_id.to_string(), + status: Self::tx_status_to_proto(tx.transaction_status).into(), + confirmed: purchase.confirmed, + created_at: Some(dt_to_proto(purchase.created_at)).into(), + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::GetPurchaseResponse { + purchase: Some(proto_purchase).into(), + ..Default::default() + })) + } + + async fn list_my_purchases( + &self, + ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::ListMyPurchasesRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let user_intents: Vec = payment_intents::table + .filter(payment_intents::user_id.eq(user_id)) + .load(&mut conn) + .unwrap_or_default(); + + let intent_ids: Vec = user_intents.iter().map(|i| i.id).collect(); + let purchases: Vec = book_purchases::table + .filter(book_purchases::transaction_id.eq_any(intent_ids)) + .load(&mut conn) + .unwrap_or_default(); + + let mut proto_purchases = Vec::new(); + for p in purchases { + let tx: Option = transactions::table.find(p.transaction_id).first(&mut conn).ok(); + let book: Option = books::table.find(p.book_id).first(&mut conn).ok(); + + if let Some(b) = book { + let status = tx + .map(|t| Self::tx_status_to_proto(t.transaction_status)) + .unwrap_or(p::TransactionStatus::TRANSACTION_STATUS_HELD); + + proto_purchases.push(p::Purchase { + id: p.transaction_id.to_string(), + transaction_id: p.transaction_id.to_string(), + book: Some(p::BookPurchaseDetails { + book_id: b.id.to_string(), + title: b.title, + cover_url: String::new(), + price_fcfa: b.price as i64, + meetup_location: None.into(), + ..Default::default() + }).into(), + buyer_id: user_id.to_string(), + status: status.into(), + confirmed: p.confirmed, + created_at: Some(dt_to_proto(p.created_at)).into(), + ..Default::default() + }); + } + } + + Ok(connectrpc::Response::new(p::ListMyPurchasesResponse { + purchases: proto_purchases, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn list_my_sales( + &self, + ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::ListMySalesRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let txs: Vec = transactions::table + .filter(transactions::recipient.eq(user_id)) + .load(&mut conn) + .unwrap_or_default(); + + let mut proto_sales = Vec::new(); + for tx in txs { + if let Ok(bp) = book_purchases::table.find(tx.payment_id).first::(&mut conn) { + if let Ok(b) = books::table.find(bp.book_id).first::(&mut conn) { + let buyer_id = payment_intents::table + .find(tx.payment_id) + .select(payment_intents::user_id) + .first::(&mut conn) + .unwrap_or(user_id); + + proto_sales.push(p::Sale { + id: bp.transaction_id.to_string(), + transaction_id: tx.payment_id.to_string(), + book: Some(p::BookPurchaseDetails { + book_id: b.id.to_string(), + title: b.title, + cover_url: String::new(), + price_fcfa: b.price as i64, + meetup_location: None.into(), + ..Default::default() + }).into(), + buyer_id: buyer_id.to_string(), + status: Self::tx_status_to_proto(tx.transaction_status).into(), + created_at: Some(dt_to_proto(tx.created_at)).into(), + ..Default::default() + }); + } + } + } + + Ok(connectrpc::Response::new(p::ListMySalesResponse { + sales: proto_sales, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn confirm_receipt( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::ConfirmReceiptRequest>, + ) -> connectrpc::ServiceResult { + let _user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let purchase_id = Uuid::parse_str(&req.purchase_id) + .map_err(|_| ConnectError::invalid_argument("invalid purchase ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + diesel::update(transactions::table.find(purchase_id)) + .set(( + transactions::transaction_status.eq(TransactionStatus::Released), + transactions::updated_at.eq(Utc::now()), + )) + .execute(&mut conn) + .map_err(|_| ConnectError::internal("failed to release escrow transaction"))?; + + diesel::update(book_purchases::table.find(purchase_id)) + .set(book_purchases::confirmed.eq(true)) + .execute(&mut conn) + .map_err(|_| ConnectError::internal("failed to confirm purchase"))?; + + let purchase: BookPurchase = book_purchases::table.find(purchase_id).first(&mut conn).map_err(|_| { + ConnectError::not_found("purchase not found") + })?; + let book: Book = books::table.find(purchase.book_id).first(&mut conn).map_err(|_| { + ConnectError::not_found("book not found") + })?; + + let proto_purchase = p::Purchase { + id: purchase.transaction_id.to_string(), + transaction_id: purchase.transaction_id.to_string(), + book: Some(p::BookPurchaseDetails { + book_id: book.id.to_string(), + title: book.title, + cover_url: String::new(), + price_fcfa: book.price as i64, + meetup_location: None.into(), + ..Default::default() + }).into(), + buyer_id: _user_id.to_string(), + status: p::TransactionStatus::TRANSACTION_STATUS_RELEASED.into(), + confirmed: true, + created_at: Some(dt_to_proto(purchase.created_at)).into(), + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::ConfirmReceiptResponse { + purchase: Some(proto_purchase).into(), + ..Default::default() + })) + } + + async fn dispute_purchase( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::DisputePurchaseRequest>, + ) -> connectrpc::ServiceResult { + let _user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let purchase_id = Uuid::parse_str(&req.purchase_id) + .map_err(|_| ConnectError::invalid_argument("invalid purchase ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + diesel::update(transactions::table.find(purchase_id)) + .set(( + transactions::transaction_status.eq(TransactionStatus::Disputed), + transactions::updated_at.eq(Utc::now()), + )) + .execute(&mut conn) + .map_err(|_| ConnectError::internal("failed to dispute escrow transaction"))?; + + let purchase: BookPurchase = book_purchases::table.find(purchase_id).first(&mut conn).map_err(|_| { + ConnectError::not_found("purchase not found") + })?; + let book: Book = books::table.find(purchase.book_id).first(&mut conn).map_err(|_| { + ConnectError::not_found("book not found") + })?; + + let proto_purchase = p::Purchase { + id: purchase.transaction_id.to_string(), + transaction_id: purchase.transaction_id.to_string(), + book: Some(p::BookPurchaseDetails { + book_id: book.id.to_string(), + title: book.title, + cover_url: String::new(), + price_fcfa: book.price as i64, + meetup_location: None.into(), + ..Default::default() + }).into(), + buyer_id: _user_id.to_string(), + status: p::TransactionStatus::TRANSACTION_STATUS_DISPUTED.into(), + confirmed: purchase.confirmed, + created_at: Some(dt_to_proto(purchase.created_at)).into(), + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::DisputePurchaseResponse { + purchase: Some(proto_purchase).into(), + ..Default::default() + })) + } +} diff --git a/backend/src/services/v1/reviews.rs b/backend/src/services/v1/reviews.rs new file mode 100644 index 0000000..c24a55e --- /dev/null +++ b/backend/src/services/v1/reviews.rs @@ -0,0 +1,210 @@ +use super::helpers::user_to_summary; +use super::proto as p; +use crate::db::Database; +use crate::middleware::AuthContextExt; +use crate::models::{NewReview, Review, User}; +use crate::schema::{reviews, uploads, users}; +use crate::utils::dt_to_proto; +use bigdecimal::BigDecimal; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct ReviewService { + db: Arc, +} + +impl ReviewService { + pub fn new(db: Arc) -> Self { + Self { db } + } +} + +impl p::ReviewService for ReviewService { + async fn create_review( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::CreateReviewRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let reviewee_id = Uuid::parse_str(&req.reviewee_id) + .map_err(|_| ConnectError::invalid_argument("invalid reviewee ID format"))?; + + let transaction_id = if !req.transaction_id.trim().is_empty() { + Uuid::parse_str(&req.transaction_id).ok() + } else { + None + }; + + if req.rating < 1 || req.rating > 5 { + return Err(ConnectError::invalid_argument("rating must be between 1 and 5")); + } + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let review_id = Uuid::now_v7(); + let new_review = NewReview { + id: review_id, + author_id: user_id, + reviewee_id: Some(reviewee_id), + transaction_id, + rating: BigDecimal::from(req.rating), + content: if req.content.trim().is_empty() { + None + } else { + Some(req.content.trim().to_string()) + }, + }; + + let rev: Review = diesel::insert_into(reviews::table) + .values(&new_review) + .get_result(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to create review"); + ConnectError::internal("failed to create review") + })?; + + // Recompute reviewee's aggregate rating in users table (since business logic lives in backend!) + let all_ratings: Vec = reviews::table + .filter(reviews::reviewee_id.eq(reviewee_id)) + .select(reviews::rating) + .load(&mut conn) + .unwrap_or_default(); + + if !all_ratings.is_empty() { + let sum: f64 = all_ratings.iter().filter_map(|r| r.to_string().parse::().ok()).sum(); + let avg = sum / (all_ratings.len() as f64); + if let Some(avg_bd) = BigDecimal::parse_bytes(format!("{:.2}", avg).as_bytes(), 10) { + let _ = diesel::update(users::table.find(reviewee_id)) + .set(users::rating.eq(avg_bd)) + .execute(&mut conn); + } + } + + let author: User = users::table.find(user_id).first(&mut conn).map_err(|_| { + ConnectError::not_found("author not found") + })?; + + let author_avatar = if let Some(av_id) = author.avatar_id { + uploads::table + .find(av_id) + .select(uploads::storage_key) + .first::(&mut conn) + .ok() + } else { + None + }; + + let proto_review = p::Review { + id: rev.id.to_string(), + author: Some(user_to_summary(author, author_avatar)).into(), + reviewee_id: req.reviewee_id, + rating: req.rating, + content: rev.content.unwrap_or_default(), + created_at: Some(dt_to_proto(rev.created_at)).into(), + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::CreateReviewResponse { + review: Some(proto_review).into(), + ..Default::default() + })) + } + + async fn list_user_reviews( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::ListUserReviewsRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let target_user_id = Uuid::parse_str(&req.user_id) + .map_err(|_| ConnectError::invalid_argument("invalid user ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let limit = if req.page_size > 0 && req.page_size <= 100 { + req.page_size as i64 + } else { + 50 + }; + + let revs: Vec = reviews::table + .filter(reviews::reviewee_id.eq(target_user_id)) + .order(reviews::created_at.desc()) + .limit(limit) + .load(&mut conn) + .unwrap_or_default(); + + let mut proto_reviews = Vec::new(); + for r in revs { + let author: Option = users::table.find(r.author_id).first(&mut conn).ok(); + let author_avatar = if let Some(ref a) = author { + if let Some(av_id) = a.avatar_id { + uploads::table + .find(av_id) + .select(uploads::storage_key) + .first::(&mut conn) + .ok() + } else { + None + } + } else { + None + }; + + let rating_int: i32 = r.rating.to_string().parse::().map(|v| v.round() as i32).unwrap_or(5); + + proto_reviews.push(p::Review { + id: r.id.to_string(), + author: author.map(|a| user_to_summary(a, author_avatar)).into(), + reviewee_id: req.user_id.clone(), + rating: rating_int, + content: r.content.unwrap_or_default(), + created_at: Some(dt_to_proto(r.created_at)).into(), + ..Default::default() + }); + } + + Ok(connectrpc::Response::new(p::ListUserReviewsResponse { + reviews: proto_reviews, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn has_reviewed_transaction( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::HasReviewedTransactionRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let tx_id = Uuid::parse_str(&req.transaction_id) + .map_err(|_| ConnectError::invalid_argument("invalid transaction ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let count: i64 = reviews::table + .filter(reviews::author_id.eq(user_id)) + .filter(reviews::transaction_id.eq(Some(tx_id))) + .count() + .get_result(&mut conn) + .unwrap_or(0); + + Ok(connectrpc::Response::new(p::HasReviewedTransactionResponse { + has_reviewed: count > 0, + ..Default::default() + })) + } +} diff --git a/backend/src/services/v1/stats.rs b/backend/src/services/v1/stats.rs new file mode 100644 index 0000000..37b7838 --- /dev/null +++ b/backend/src/services/v1/stats.rs @@ -0,0 +1,59 @@ +use super::proto as p; +use crate::db::Database; +use crate::models::BookStatus; +use crate::schema::{books, users}; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; + +pub struct StatsService { + db: Arc, +} + +impl StatsService { + pub fn new(db: Arc) -> Self { + Self { db } + } +} + +impl p::StatsService for StatsService { + async fn get_platform_stats( + &self, + _ctx: connectrpc::RequestContext, + _request: connectrpc::ServiceRequest<'_, p::GetPlatformStatsRequest>, + ) -> connectrpc::ServiceResult { + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let circulated_books: i64 = books::table + .filter(books::status.eq(BookStatus::Sold)) + .count() + .get_result(&mut conn) + .unwrap_or(0); + + let total_users: i64 = users::table + .filter(users::deleted_at.is_null()) + .count() + .get_result(&mut conn) + .unwrap_or(0); + + // Average savings estimated at 3500 FCFA per circulated book, 2.7kg CO2 avoided per book + let money_saved = circulated_books * 3500; + let co2_avoided = (circulated_books as f64) * 2.7; + + let stats = p::PlatformStats { + total_books_circulated: circulated_books, + total_students_reached: total_users, + total_money_saved_fcfa: money_saved, + total_co2_avoided_kg: co2_avoided, + ..Default::default() + }; + + Ok(connectrpc::Response::new(p::GetPlatformStatsResponse { + stats: Some(stats).into(), + ..Default::default() + })) + } +} diff --git a/backend/src/services/v1/uploads.rs b/backend/src/services/v1/uploads.rs new file mode 100644 index 0000000..ed91eca --- /dev/null +++ b/backend/src/services/v1/uploads.rs @@ -0,0 +1,151 @@ +use super::proto as p; +use crate::db::Database; +use crate::middleware::AuthContextExt; +use crate::models::{NewUpload, Upload}; +use crate::schema::uploads; +use crate::utils::dt_to_proto; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct UploadService { + db: Arc, +} + +impl UploadService { + pub fn new(db: Arc) -> Self { + Self { db } + } + + fn upload_to_proto(u: Upload) -> p::Upload { + p::Upload { + id: u.id.to_string(), + storage_key: u.storage_key.clone(), + file_name: u.file_name, + content_type: u.content_type, + size_bytes: u.size_bytes, + url: format!("/uploads/{}", u.storage_key), + created_at: Some(dt_to_proto(u.created_at)).into(), + ..Default::default() + } + } +} + +impl p::UploadService for UploadService { + async fn create_upload( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::CreateUploadRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id().ok(); + let req = request.to_owned_message(); + + if req.file_name.trim().is_empty() { + return Err(ConnectError::invalid_argument("file_name is required")); + } + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let upload_id = Uuid::now_v7(); + let storage_key = format!("{}-{}", upload_id, req.file_name.trim()); + let new_upload = NewUpload { + id: upload_id, + storage_key: storage_key.clone(), + file_name: req.file_name.trim().to_string(), + content_type: if req.content_type.is_empty() { + "application/octet-stream".to_string() + } else { + req.content_type + }, + size_bytes: if req.size_bytes > 0 { req.size_bytes } else { 1 }, + uploaded_by: user_id, + }; + + let u: Upload = diesel::insert_into(uploads::table) + .values(&new_upload) + .get_result(&mut conn) + .map_err(|err| { + tracing::error!(%err, "Failed to insert upload"); + ConnectError::internal("failed to register upload") + })?; + + let upload_url = format!("/api/v1/uploads/{}/bytes", upload_id); + Ok(connectrpc::Response::new(p::CreateUploadResponse { + upload: Some(Self::upload_to_proto(u)).into(), + upload_url, + ..Default::default() + })) + } + + async fn complete_upload( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::CompleteUploadRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let upload_id = Uuid::parse_str(&req.upload_id) + .map_err(|_| ConnectError::invalid_argument("invalid upload ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let u: Upload = uploads::table + .find(upload_id) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("upload not found"))?; + + Ok(connectrpc::Response::new(p::CompleteUploadResponse { + upload: Some(Self::upload_to_proto(u)).into(), + ..Default::default() + })) + } + + async fn get_upload( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::GetUploadRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let upload_id = Uuid::parse_str(&req.upload_id) + .map_err(|_| ConnectError::invalid_argument("invalid upload ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let u: Upload = uploads::table + .find(upload_id) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("upload not found"))?; + + Ok(connectrpc::Response::new(p::GetUploadResponse { + upload: Some(Self::upload_to_proto(u)).into(), + ..Default::default() + })) + } + + async fn delete_upload( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::DeleteUploadRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let upload_id = Uuid::parse_str(&req.upload_id) + .map_err(|_| ConnectError::invalid_argument("invalid upload ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let _ = diesel::delete(uploads::table.find(upload_id)).execute(&mut conn); + Ok(connectrpc::Response::new(p::DeleteUploadResponse::default())) + } +} diff --git a/backend/src/services/v1/users.rs b/backend/src/services/v1/users.rs new file mode 100644 index 0000000..c72d7de --- /dev/null +++ b/backend/src/services/v1/users.rs @@ -0,0 +1,58 @@ +use super::helpers::user_to_summary; +use super::proto as p; +use crate::db::Database; +use crate::models::User; +use crate::schema::{uploads, users}; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct UserService { + db: Arc, +} + +impl UserService { + pub fn new(db: Arc) -> Self { + Self { db } + } +} + +impl p::UserService for UserService { + async fn get_user( + &self, + _ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::GetUserRequest>, + ) -> connectrpc::ServiceResult { + let req = request.to_owned_message(); + let user_id = Uuid::parse_str(&req.user_id) + .map_err(|_| ConnectError::invalid_argument("invalid user ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let user: User = users::table + .find(user_id) + .filter(users::deleted_at.is_null()) + .first(&mut conn) + .map_err(|_| ConnectError::not_found("user not found"))?; + + let avatar_url = if let Some(avatar_id) = user.avatar_id { + uploads::table + .find(avatar_id) + .select(uploads::storage_key) + .first::(&mut conn) + .ok() + } else { + None + }; + + let summary = user_to_summary(user, avatar_url); + Ok(connectrpc::Response::new(p::GetUserResponse { + user: Some(summary).into(), + ..Default::default() + })) + } +} diff --git a/backend/src/services/v1/wishlist.rs b/backend/src/services/v1/wishlist.rs new file mode 100644 index 0000000..5bb8fe8 --- /dev/null +++ b/backend/src/services/v1/wishlist.rs @@ -0,0 +1,239 @@ +use super::helpers::{ + book_condition_to_proto, book_picture_type_to_proto, book_status_to_proto, user_to_summary, +}; +use super::proto as p; +use crate::db::Database; +use crate::middleware::AuthContextExt; +use crate::models::{Book, BookCategory, BookPicture, IndexedLocation, NewWishlistItem, Upload, User, WishlistItem}; +use crate::schema::{ + book_categories, book_pictures, books, indexed_locations, uploads, users, wishlist_items, +}; +use crate::utils::dt_to_proto; +use connectrpc::error::ConnectError; +use diesel::prelude::*; +use std::sync::Arc; +use uuid::Uuid; + +pub struct WishlistService { + db: Arc, +} + +impl WishlistService { + pub fn new(db: Arc) -> Self { + Self { db } + } + + fn load_full_book( + &self, + conn: &mut crate::db::PgPooledConnection, + book: Book, + ) -> Result { + let seller: User = users::table + .find(book.seller_id) + .first(conn) + .map_err(|_| ConnectError::not_found("seller not found"))?; + + let seller_avatar = if let Some(avatar_id) = seller.avatar_id { + uploads::table + .find(avatar_id) + .select(uploads::storage_key) + .first::(conn) + .ok() + } else { + None + }; + + let category: BookCategory = book_categories::table + .find(book.category) + .first(conn) + .unwrap_or(BookCategory { + id: book.category, + name: "General".to_string(), + }); + + let pictures: Vec<(BookPicture, Upload)> = book_pictures::table + .filter(book_pictures::book_id.eq(book.id)) + .inner_join(uploads::table.on(book_pictures::upload_id.eq(uploads::id))) + .load::<(BookPicture, Upload)>(conn) + .unwrap_or_default(); + + let proto_pictures = pictures + .into_iter() + .map(|(bp, up)| p::BookPicture { + upload_id: bp.upload_id.to_string(), + url: up.storage_key, + r#type: book_picture_type_to_proto(bp.type_).into(), + ..Default::default() + }) + .collect(); + + let location = if let Some(loc_id) = book.location { + indexed_locations::table + .find(loc_id) + .first::(conn) + .ok() + .map(|loc| p::LatLng { + latitude: loc.latitude, + longitude: loc.longitude, + ..Default::default() + }) + } else { + None + }; + + Ok(p::Book { + id: book.id.to_string(), + seller: Some(user_to_summary(seller, seller_avatar)).into(), + title: book.title, + author: book.author, + price_fcfa: book.price as i64, + condition: book_condition_to_proto(book.condition).into(), + description: book.description.unwrap_or_default(), + status: book_status_to_proto(book.status).into(), + category: Some(p::BookCategory { + id: category.id, + name: category.name, + ..Default::default() + }) + .into(), + refundable: book.refundable, + swapable: book.swapable, + pictures: proto_pictures, + ebook_id: book.ebook_id.map(|id| id.to_string()).unwrap_or_default(), + boost_expires_at: Some(dt_to_proto(book.boost_expires_at)).into(), + expires_at: Some(dt_to_proto(book.expires_at)).into(), + created_at: Some(dt_to_proto(book.created_at)).into(), + updated_at: Some(dt_to_proto(book.updated_at)).into(), + location: location.into(), + ..Default::default() + }) + } +} + +impl p::WishlistService for WishlistService { + async fn list_wishlist( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::ListWishlistRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let limit = if req.page_size > 0 && req.page_size <= 100 { + req.page_size as i64 + } else { + 50 + }; + + let items: Vec = wishlist_items::table + .filter(wishlist_items::user_id.eq(user_id)) + .order(wishlist_items::created_at.desc()) + .limit(limit) + .load(&mut conn) + .unwrap_or_default(); + + let mut proto_books = Vec::new(); + for item in items { + if let Ok(b) = books::table.find(item.book_id).first::(&mut conn) { + if let Ok(pb) = self.load_full_book(&mut conn, b) { + proto_books.push(pb); + } + } + } + + Ok(connectrpc::Response::new(p::ListWishlistResponse { + books: proto_books, + next_page_token: String::new(), + ..Default::default() + })) + } + + async fn add_book_to_wishlist( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::AddBookToWishlistRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let new_item = NewWishlistItem { user_id, book_id }; + let _ = diesel::insert_into(wishlist_items::table) + .values(&new_item) + .on_conflict_do_nothing() + .execute(&mut conn); + + Ok(connectrpc::Response::new(p::AddBookToWishlistResponse { + added: true, + ..Default::default() + })) + } + + async fn remove_book_from_wishlist( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::RemoveBookFromWishlistRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let count = diesel::delete( + wishlist_items::table + .filter(wishlist_items::user_id.eq(user_id)) + .filter(wishlist_items::book_id.eq(book_id)), + ) + .execute(&mut conn) + .unwrap_or(0); + + Ok(connectrpc::Response::new(p::RemoveBookFromWishlistResponse { + removed: count > 0, + ..Default::default() + })) + } + + async fn is_book_in_wishlist( + &self, + ctx: connectrpc::RequestContext, + request: connectrpc::ServiceRequest<'_, p::IsBookInWishlistRequest>, + ) -> connectrpc::ServiceResult { + let user_id = ctx.user_id()?; + let req = request.to_owned_message(); + let book_id = Uuid::parse_str(&req.book_id) + .map_err(|_| ConnectError::invalid_argument("invalid book ID format"))?; + + let mut conn = self.db.get_conn().map_err(|err| { + tracing::error!(%err, "DB connection error"); + ConnectError::internal("database connection error") + })?; + + let count: i64 = wishlist_items::table + .filter(wishlist_items::user_id.eq(user_id)) + .filter(wishlist_items::book_id.eq(book_id)) + .count() + .get_result(&mut conn) + .unwrap_or(0); + + Ok(connectrpc::Response::new(p::IsBookInWishlistResponse { + is_favorite: count > 0, + ..Default::default() + })) + } +} diff --git a/backend/src/utils.rs b/backend/src/utils.rs new file mode 100644 index 0000000..cfbba53 --- /dev/null +++ b/backend/src/utils.rs @@ -0,0 +1,39 @@ +use chrono::{DateTime, Utc}; +use rand::RngExt; +use sha2::{Digest, Sha256}; + +pub fn hash_sha256(input: &[u8]) -> Vec { + let mut hasher = Sha256::new(); + hasher.update(input); + hasher.finalize().to_vec() +} + +pub fn generate_random_bytes(len: usize) -> Vec { + let mut bytes = vec![0u8; len]; + rand::rng().fill(&mut bytes[..]); + bytes +} + +pub fn generate_random_token() -> String { + let bytes = generate_random_bytes(32); + // Simple hex string without extra hex crate if not needed or with fmt + bytes.iter().map(|b| format!("{b:02x}")).collect() +} + +pub fn dt_to_proto(dt: DateTime) -> buffa_types::google::protobuf::Timestamp { + buffa_types::google::protobuf::Timestamp { + seconds: dt.timestamp(), + nanos: dt.timestamp_subsec_nanos() as i32, + ..Default::default() + } +} + +pub fn opt_dt_to_proto( + opt: Option>, +) -> buffa::MessageField< + buffa_types::google::protobuf::Timestamp, + buffa::Inline, +> { + opt.map(dt_to_proto).into() +} + diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 0000000..64238f7 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,12 @@ +version: v2 +plugins: + - local: protoc-gen-buffa + out: backend/src/proto/buf + opt: + - file_per_package=true + - json=true + - local: protoc-gen-connect-rust + out: backend/src/proto/svc + opt: + - file_per_package + - extern_path=.=crate::proto::buf diff --git a/proto/v1/auth.proto b/proto/v1/auth.proto index 7887581..1776c24 100644 --- a/proto/v1/auth.proto +++ b/proto/v1/auth.proto @@ -4,7 +4,6 @@ package bookbridge.v1; import "google/protobuf/timestamp.proto"; -// Full user record as seen by the user themselves (maps to the users table). message User { string id = 1; string email = 2; @@ -21,10 +20,7 @@ message User { message Session { string session_id = 1; User user = 2; - // Short-lived stateless access token (JWT) for authorizing API calls. string access_token = 3; - // Opaque, single-use secret used to obtain new access tokens. Sent only - // when the session is created or refreshed; never returned on reads. string refresh_token = 4; google.protobuf.Timestamp access_token_expires_at = 5; google.protobuf.Timestamp expires_at = 6; From beed8c987db1565b65257eaeeb61c8b1c1790b19 Mon Sep 17 00:00:00 2001 From: ken-morel Date: Wed, 16 Sep 2026 13:10:18 +0530 Subject: [PATCH 4/4] weft: Weftization Signed-off-by: ken-morel Change-Id: I5f27a4f2720da75dc9234a258d74f6c96a6a6964 --- weft/app.build-apk.sh | 8 ++++ weft/app.build-web.sh | 8 ++++ weft/app.run-web.sh | 6 +++ weft/backend.build.sh | 9 ++++ weft/backend.migrate.sh | 6 +++ weft/backend.run.sh | 6 +++ weft/install-bun.sh | 6 +++ weft/web.build.sh | 10 +++++ weft/web.run.sh | 20 +++++++++ weft/weft.zon | 97 +++++++++++++++++++++++++++++++++++++++++ 10 files changed, 176 insertions(+) create mode 100755 weft/app.build-apk.sh create mode 100755 weft/app.build-web.sh create mode 100755 weft/app.run-web.sh create mode 100755 weft/backend.build.sh create mode 100755 weft/backend.migrate.sh create mode 100755 weft/backend.run.sh create mode 100755 weft/install-bun.sh create mode 100755 weft/web.build.sh create mode 100755 weft/web.run.sh create mode 100644 weft/weft.zon diff --git a/weft/app.build-apk.sh b/weft/app.build-apk.sh new file mode 100755 index 0000000..fe88b43 --- /dev/null +++ b/weft/app.build-apk.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +source ~/.bashrc + +cp -r $IN/src.app/* ./ + +flutter build apk + +cp -r build/apk/* $OUT/app.build-apk/ diff --git a/weft/app.build-web.sh b/weft/app.build-web.sh new file mode 100755 index 0000000..e6e3f2b --- /dev/null +++ b/weft/app.build-web.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +source ~/.bashrc + +cp -r $IN/src.app/* ./ + +flutter build web + +cp -r build/web/* $OUT/app.build-web/ diff --git a/weft/app.run-web.sh b/weft/app.run-web.sh new file mode 100755 index 0000000..eb93491 --- /dev/null +++ b/weft/app.run-web.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +cp -r $IN/app.build-web/* ./ +cp $IN/src.app.web/mobile-server.js ./ + +bun mobile-server.js diff --git a/weft/backend.build.sh b/weft/backend.build.sh new file mode 100755 index 0000000..f0b6b2e --- /dev/null +++ b/weft/backend.build.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +source ~/.bashrc + +cp -r $IN/src.backend/* ./ + +cargo build --release + +cp target/release/backend $OUT/backend.build/ diff --git a/weft/backend.migrate.sh b/weft/backend.migrate.sh new file mode 100755 index 0000000..735501c --- /dev/null +++ b/weft/backend.migrate.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +cp $IN/backend.build/backend ./ + +chmod +x ./backend +./backend migrate diff --git a/weft/backend.run.sh b/weft/backend.run.sh new file mode 100755 index 0000000..957883d --- /dev/null +++ b/weft/backend.run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +cp $IN/backend.build/backend ./ + +chmod +x ./backend +./backend diff --git a/weft/install-bun.sh b/weft/install-bun.sh new file mode 100755 index 0000000..a25d55b --- /dev/null +++ b/weft/install-bun.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +curl -fsSL https://bun.sh/install | bash + +echo 'export BUN_INSTALL="$HOME/.bun"' >> ~/.bashrc +echo 'export PATH="$BUN_INSTALL/bin:$PATH"' >> ~/.bashrc diff --git a/weft/web.build.sh b/weft/web.build.sh new file mode 100755 index 0000000..47b882c --- /dev/null +++ b/weft/web.build.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +source ~/.bashrc + +cp -r $IN/src.web/* ./ + +bun install +bun run build + +cp -r build/* $OUT/web.build/ diff --git a/weft/web.run.sh b/weft/web.run.sh new file mode 100755 index 0000000..94fe574 --- /dev/null +++ b/weft/web.run.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +source ~/.bashrc + +cp -r $IN/web.build/* ./ + +for i in {1..10}; do + bun . + + status=$? + if [ $status -eq 0 ]; then + break + fi + echo "Attempt $i failed with exit code $status. Retrying..." + sleep 5 +done +if [ $status -ne 0 ]; then + echo "Command failed 10 times. Exiting with status $status." + exit $status +fi diff --git a/weft/weft.zon b/weft/weft.zon new file mode 100644 index 0000000..b8ee103 --- /dev/null +++ b/weft/weft.zon @@ -0,0 +1,97 @@ +.{ + .workspace = "bookbridge", + .env = .{}, + .sources = .{ + .{ "web", "web/" }, + .{ "backend", "backend/" }, + .{ "app", "app/" }, + .{ "app.web", "app/web/" }, + }, + .pipelines = .{ + // /backend + .{ + .name = "backend.build", + .in = .{"src.backend"}, + .keep = .{ + .{ "backend-target", "target/" }, + }, + .second_instance = .kill, + }, + .{ + .name = "backend.migrate", + .in = .{"backend.build"}, + .required_env = .{"DATABASE_URL"}, + .second_instance = .fail, + }, + .{ + .name = "backend.run", + .in = .{"backend.build"}, + .out = .{"backend.run"}, + .required_env = .{ "ADMIN_TOTP_SECRET", "JWT_SECRET" }, + .env = .{ + .{ "PORT", "3040" }, + .{ "DATABASE_URL", "postgresql://postgres:@localhost:5432/bookbridge" }, + }, + .second_instance = .kill, + }, + // /web + .{ + .name = "install-bun", + .second_instance = .fail, + }, + .{ + .name = "web.build", + .in = .{"src.web"}, + .keep = .{ + .{ "web-modules", "node_modules/" }, + }, + }, + .{ + .name = "web.run", + .in = .{"web.build"}, + .second_instance = .kill, + .env = .{ + .{ "BACKEND_URL", "http://localhost:3040" }, + .{ "PORT", "3000" }, + }, + }, + // /app + .{ + .name = "app.build-web", + .in = .{"src.app"}, + .second_instance = .kill, + .keep = .{ + .{ "app-build", "build/" }, + }, + }, + .{ + .name = "app.run-web", + .env = .{ + .{ "PORT", "3004" }, + }, + .in = .{ "app.build-web", "src.app.web" }, + .out = .{"app.run-web"}, + .second_instance = .kill, + }, + .{ + .name = "app.build-apk", + .in = .{"src.app"}, + .out = .{"app-apk"}, + .second_instance = .kill, + .keep = .{ + .{ "app-build", "build/" }, + }, + }, + // /alias + .{ + .name = "build", + .in = .{ "backend.build", "web.build", "app.build-web" }, + .run = .nothing, + }, + .{ + .name = "run", + .in = .{ "backend.run", "web.run", "app.run-web" }, + .run = .nothing, + }, + }, +}