git-bug 0.2.4

A rust library for interfacing with git-bug repositories
Documentation
// git-bug-rs - A rust library for interfacing with git-bug repositories
//
// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This file is part of git-bug-rs/git-gub.
//
// You should have received a copy of the License along with this program.
// If not, see <https://www.gnu.org/licenses/agpl.txt>.

use simd_json::{
    derived::{ValueTryIntoArray, ValueTryIntoString},
    owned,
};

use crate::{
    entities::issue::{
        Issue,
        issue_operation::{File, IssueOperationData},
    },
    replica::entity::{
        id::{Id, entity_id::EntityId},
        operation::operation_data::get,
    },
};

struct EditComment {
    target: String,
    message: String,
    files: Option<Vec<owned::Value>>,
}

pub(crate) fn edit_comment(
    mut value: owned::Object,
) -> Result<IssueOperationData, super::decode::Error> {
    let base: EditComment = EditComment {
        target: get! {value, "target", try_into_string, super::decode::Error},
        message: get! {value, "message", try_into_string, super::decode::Error},
        files: get! {@option value, "files", try_into_array, super::decode::Error},
    };

    Ok(IssueOperationData::EditComment {
        target: unsafe {
            // Safety:
            // - We know that this operation can only be used in an Issue.
            // - We don't know, however, that the id is valid, we just have to trust the data.
            EntityId::from_id(Id::from_hex(base.target.as_bytes())?)
        },
        message: base.message,
        files: {
            base.files
                .unwrap_or_default()
                .into_iter()
                .map(|file_id| File::try_from(&file_id))
                .collect::<Result<_, _>>()?
        },
    })
}

pub(crate) fn edit_comment_value<'a>(
    target: &'a EntityId<Issue>,
    message: &'a str,
    files: &'a [File],
) -> simd_json::borrowed::Object<'a> {
    let files: Option<Vec<String>> = if files.is_empty() {
        None
    } else {
        Some(files.iter().map(File::to_string).collect())
    };

    let mut object = simd_json::borrowed::Object::new();

    // Safety:
    // We just created this object. As such, it is empty.
    unsafe {
        object.insert_nocheck("target".into(), target.to_string().into());
        object.insert_nocheck("message".into(), message.into());
        object.insert_nocheck("files".into(), files.into());
    }

    object
}